Pulled in libffi from gcc trunk.

Fixed build and install for standalone use.
This commit is contained in:
tromey
2006-12-24 23:12:15 +00:00
parent e7ba089659
commit e680ecfbfc
222 changed files with 68102 additions and 11622 deletions

252
libffi/src/alpha/ffi.c Normal file
View File

@@ -0,0 +1,252 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998, 2001 Red Hat, Inc.
Alpha 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
extern void ffi_closure_osf(void);
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Adjust cif->bytes to represent a minimum 6 words for the temporary
register argument loading area. */
if (cif->bytes < 6*FFI_SIZEOF_ARG)
cif->bytes = 6*FFI_SIZEOF_ARG;
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_STRUCT:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
cif->flags = cif->rtype->type;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
void
ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **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->flags == FFI_TYPE_STRUCT)
rvalue = alloca(cif->rtype->size);
/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
argp = stack = alloca(cif->bytes + 4*FFI_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, FFI_SIZEOF_ARG) / FFI_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.
Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
instead, since both Compaq as and gas can handle it.
0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
asm volatile ("call_pal 0x86" : : : "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, FFI_SIZEOF_ARG) / FFI_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

@@ -0,0 +1,48 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for Alpha.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
FFI_OSF,
FFI_DEFAULT_ABI = FFI_OSF,
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0
#endif

359
libffi/src/alpha/osf.S Normal file
View File

@@ -0,0 +1,359 @@
/* -----------------------------------------------------------------------
osf.S - Copyright (c) 1998, 2001 Red Hat
Alpha/OSF Foreign Function Interface
$Id: osf.S,v 1.5 2008/01/29 12:28:14 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
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 <fficonfig.h>
#include <ffi.h>
.arch ev6
.text
/* 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:
.frame $15, 32, $26, 0
.mask 0x4008000, -32
$LFB1:
addq $16,$17,$1
mov $16, $30
stq $26, 0($1)
stq $15, 8($1)
stq $18, 16($1)
mov $1, $15
$LCFI1:
.prologue 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 $21, 40($30)
# Deallocate the register argument area.
lda $30, 48($30)
jsr $26, ($27), 0
ldgp $29, 0($26)
# If the return value pointer is NULL, assume no return value.
ldq $19, 24($15)
ldq $18, 16($15)
ldq $26, 0($15)
$LCFI2:
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
.align 3
$noretval:
ldq $15, 8($15)
ret
.align 4
$retint:
stq $0, 0($19)
nop
ldq $15, 8($15)
ret
.align 4
$retfloat:
sts $f0, 0($19)
nop
ldq $15, 8($15)
ret
.align 4
$retdouble:
stt $f0, 0($19)
nop
ldq $15, 8($15)
ret
$LFE1:
.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
$LFB2:
ldgp $29, 0($27)
subq $30, 16*8, $30
$LCFI5:
stq $26, 0($30)
$LCFI6:
.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
$LFE2:
.end ffi_closure_osf
#ifdef __ELF__
.section .rodata
#else
.rdata
#endif
$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
#ifdef __ELF__
.section .eh_frame,EH_FRAME_FLAGS,@progbits
__FRAME_BEGIN__:
.4byte $LECIE1-$LSCIE1 # Length of Common Information Entry
$LSCIE1:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x78 # sleb128 -8; CIE Data Alignment Factor
.byte 26 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x1b # FDE Encoding (pcrel sdata4)
.byte 0xc # DW_CFA_def_cfa
.byte 30 # uleb128 column 30
.byte 0 # uleb128 offset 0
.align 3
$LECIE1:
$LSFDE1:
.4byte $LEFDE1-$LASFDE1 # FDE Length
$LASFDE1:
.4byte $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset
.4byte $LFB1-. # FDE initial location
.4byte $LFE1-$LFB1 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI1-$LFB1
.byte 0x9a # DW_CFA_offset, column 26
.byte 4 # uleb128 4*-8
.byte 0x8f # DW_CFA_offset, column 15
.byte 0x3 # uleb128 3*-8
.byte 0xc # DW_CFA_def_cfa
.byte 15 # uleb128 column 15
.byte 32 # uleb128 offset 32
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI2-$LCFI1
.byte 0xda # DW_CFA_restore, column 26
.align 3
$LEFDE1:
$LSFDE3:
.4byte $LEFDE3-$LASFDE3 # FDE Length
$LASFDE3:
.4byte $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset
.4byte $LFB2-. # FDE initial location
.4byte $LFE2-$LFB2 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI5-$LFB2
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x80,0x1 # uleb128 128
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI6-$LCFI5
.byte 0x9a # DW_CFA_offset, column 26
.byte 16 # uleb128 offset 16*-8
.align 3
$LEFDE3:
#endif

170
libffi/src/arm/ffi.c Normal file
View File

@@ -0,0 +1,170 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Red Hat, Inc.
ARM 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* 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)
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) {
*(void **) argp = ecif->rvalue;
argp += 4;
}
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
(i != 0);
i--, p_arg++)
{
size_t z;
/* Align if necessary */
if (((*p_arg)->alignment - 1) & (unsigned) argp) {
argp = (char *) ALIGN(argp, (*p_arg)->alignment);
}
z = (*p_arg)->size;
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);
break;
case FFI_TYPE_STRUCT:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else if (z == sizeof(int))
{
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
}
else
{
memcpy(argp, *p_argv, z);
}
p_argv++;
argp += z;
}
return;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Round the stack up to a multiple of 8 bytes. This isn't needed
everywhere, but it is on some platforms, and it doesn't harm anything
when it isn't needed. */
cif->bytes = (cif->bytes + 7) & ~7;
/* 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:
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags = (unsigned) FFI_TYPE_SINT64;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)());
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;
}
}

View File

@@ -0,0 +1,47 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for ARM.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#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 0
#define FFI_NATIVE_RAW_API 0
#endif

209
libffi/src/arm/sysv.S Normal file
View File

@@ -0,0 +1,209 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1998 Red Hat, Inc.
ARM 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 <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
/* We need a better way of testing for this, but for now, this is all
we can do. */
@ This selects the minimum architecture level required.
#define __ARM_ARCH__ 3
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 4
#endif
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5TEJ__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 5
#endif
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 6
#endif
#if __ARM_ARCH__ >= 5
# define call_reg(x) blx x
#elif defined (__ARM_ARCH_4T__)
# define call_reg(x) mov lr, pc ; bx x
# if defined(__thumb__) || defined(__THUMB_INTERWORK__)
# define __INTERWORKING__
# endif
#else
# define call_reg(x) mov lr, pc ; mov pc, x
#endif
#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
.macro ARM_FUNC_START name
.text
.align 0
.thumb
.thumb_func
ENTRY(\name)
bx pc
nop
.arm
/* A hook to tell gdb that we've switched to ARM mode. Also used to call
directly from other local arm routines. */
_L__\name:
.endm
#else
.macro ARM_FUNC_START name
.text
.align 0
.arm
ENTRY(\name)
.endm
#endif
.macro RETLDM regs=, cond=, dirn=ia
#if defined (__INTERWORKING__)
.ifc "\regs",""
ldr\cond lr, [sp], #4
.else
ldm\cond\dirn sp!, {\regs, lr}
.endif
bx\cond lr
#else
.ifc "\regs",""
ldr\cond pc, [sp], #4
.else
ldm\cond\dirn sp!, {\regs, pc}
.endif
#endif
.endm
@ r0: ffi_prep_args
@ r1: &ecif
@ r2: cif->bytes
@ r3: fig->flags
@ sp+0: ecif.rvalue
@ sp+4: fn
@ This assumes we are using gas.
ARM_FUNC_START ffi_call_SYSV
@ Save registers
stmfd sp!, {r0-r3, fp, lr}
mov fp, sp
@ Make room for all of the new args.
sub sp, fp, r2
@ Place all of the ffi_prep_args in position
mov ip, r0
mov r0, sp
@ r1 already set
@ Call ffi_prep_args(stack, &ecif)
call_reg(ip)
@ move first 4 parameters in registers
ldmia sp, {r0-r3}
@ and adjust stack
ldr ip, [fp, #8]
cmp ip, #16
movhs ip, #16
add sp, sp, ip
@ call (fn) (...)
ldr ip, [fp, #28]
call_reg(ip)
@ Remove the space we pushed for the args
mov sp, fp
@ Load r2 with the pointer to storage for the return value
ldr r2, [sp, #24]
@ Load r3 with the return type code
ldr r3, [sp, #12]
@ If the return value pointer is NULL, assume no return value.
cmp r2, #0
beq LSYM(Lepilogue)
@ return INT
cmp r3, #FFI_TYPE_INT
#ifdef __SOFTFP__
cmpne r3, #FFI_TYPE_FLOAT
#endif
streq r0, [r2]
beq LSYM(Lepilogue)
@ return INT64
cmp r3, #FFI_TYPE_SINT64
#ifdef __SOFTFP__
cmpne r3, #FFI_TYPE_DOUBLE
#endif
stmeqia r2, {r0, r1}
#ifndef __SOFTFP__
beq LSYM(Lepilogue)
@ return FLOAT
cmp r3, #FFI_TYPE_FLOAT
stfeqs f0, [r2]
beq LSYM(Lepilogue)
@ return DOUBLE or LONGDOUBLE
cmp r3, #FFI_TYPE_DOUBLE
stfeqd f0, [r2]
#endif
LSYM(Lepilogue):
RETLDM "r0-r3,fp"
.ffi_call_SYSV_end:
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)

381
libffi/src/cris/ffi.c Normal file
View File

@@ -0,0 +1,381 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Cygnus Solutions
Copyright (c) 2004 Simon Posnjak
Copyright (c) 2005 Axis Communications AB
CRIS 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>
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
static ffi_status
initialize_aggregate_packed_struct (ffi_type * arg)
{
ffi_type **ptr;
FFI_ASSERT (arg != NULL);
FFI_ASSERT (arg->elements != NULL);
FFI_ASSERT (arg->size == 0);
FFI_ASSERT (arg->alignment == 0);
ptr = &(arg->elements[0]);
while ((*ptr) != NULL)
{
if (((*ptr)->size == 0)
&& (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
FFI_ASSERT (ffi_type_test ((*ptr)));
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
arg->alignment : (*ptr)->alignment;
ptr++;
}
if (arg->size == 0)
return FFI_BAD_TYPEDEF;
else
return FFI_OK;
}
int
ffi_prep_args (char *stack, extended_cif * ecif)
{
unsigned int i;
unsigned int struct_count = 0;
void **p_argv;
char *argp;
ffi_type **p_arg;
argp = stack;
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
(i != 0); i--, p_arg++)
{
size_t z;
switch ((*p_arg)->type)
{
case FFI_TYPE_STRUCT:
{
z = (*p_arg)->size;
if (z <= 4)
{
memcpy (argp, *p_argv, z);
z = 4;
}
else if (z <= 8)
{
memcpy (argp, *p_argv, z);
z = 8;
}
else
{
unsigned int uiLocOnStack;
z = sizeof (void *);
uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
struct_count = struct_count + (*p_arg)->size;
*(unsigned int *) argp =
(unsigned int) (UINT32 *) (stack + uiLocOnStack);
memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
}
break;
}
default:
z = (*p_arg)->size;
if (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);
break;
default:
FFI_ASSERT (0);
}
z = sizeof (int);
}
else if (z == sizeof (int))
*(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
else
memcpy (argp, *p_argv, z);
break;
}
p_argv++;
argp += z;
}
return (struct_count);
}
ffi_status
ffi_prep_cif (ffi_cif * cif,
ffi_abi abi, unsigned int nargs,
ffi_type * rtype, ffi_type ** atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT (cif != NULL);
FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->rtype = rtype;
cif->flags = 0;
if ((cif->rtype->size == 0)
&& (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
return FFI_BAD_TYPEDEF;
FFI_ASSERT_VALID_TYPE (cif->rtype);
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
if (((*ptr)->size == 0)
&& (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
FFI_ASSERT_VALID_TYPE (*ptr);
if (((*ptr)->alignment - 1) & bytes)
bytes = ALIGN (bytes, (*ptr)->alignment);
if ((*ptr)->type == FFI_TYPE_STRUCT)
{
if ((*ptr)->size > 8)
{
bytes += (*ptr)->size;
bytes += sizeof (void *);
}
else
{
if ((*ptr)->size > 4)
bytes += 8;
else
bytes += 4;
}
}
else
bytes += STACK_ARG_SIZE ((*ptr)->size);
}
cif->bytes = bytes;
return ffi_prep_cif_machdep (cif);
}
ffi_status
ffi_prep_cif_machdep (ffi_cif * cif)
{
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags = (unsigned) cif->rtype->type;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
extended_cif *,
unsigned, unsigned, unsigned *, void (*fn) ())
__attribute__ ((__visibility__ ("hidden")));
void
ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
{
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
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;
}
}
/* Because the following variables are not exported outside libffi, we
mark them hidden. */
/* Assembly code for the jump stub. */
extern const char ffi_cris_trampoline_template[]
__attribute__ ((__visibility__ ("hidden")));
/* Offset into ffi_cris_trampoline_template of where to put the
ffi_prep_closure_inner function. */
extern const int ffi_cris_trampoline_fn_offset
__attribute__ ((__visibility__ ("hidden")));
/* Offset into ffi_cris_trampoline_template of where to put the
closure data. */
extern const int ffi_cris_trampoline_closure_offset
__attribute__ ((__visibility__ ("hidden")));
/* This function is sibling-called (jumped to) by the closure
trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
PARAMS[4] to simplify handling of a straddling parameter. A copy
of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are
put at the appropriate place in CLOSURE which is then executed and
the return value is passed back to the caller. */
static unsigned long long
ffi_prep_closure_inner (void **params, ffi_closure* closure)
{
char *register_args = (char *) params;
void *struct_ret = params[5];
char *stack_args = params[6];
char *ptr = register_args;
ffi_cif *cif = closure->cif;
ffi_type **arg_types = cif->arg_types;
/* Max room needed is number of arguments as 64-bit values. */
void **avalue = alloca (closure->cif->nargs * sizeof(void *));
int i;
int doing_regs;
long long llret = 0;
/* Find the address of each argument. */
for (i = 0, doing_regs = 1; i < cif->nargs; i++)
{
/* Types up to and including 8 bytes go by-value. */
if (arg_types[i]->size <= 4)
{
avalue[i] = ptr;
ptr += 4;
}
else if (arg_types[i]->size <= 8)
{
avalue[i] = ptr;
ptr += 8;
}
else
{
FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
/* Passed by-reference, so copy the pointer. */
avalue[i] = *(void **) ptr;
ptr += 4;
}
/* If we've handled more arguments than fit in registers, start
looking at the those passed on the stack. Step over the
first one if we had a straddling parameter. */
if (doing_regs && ptr >= register_args + 4*4)
{
ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
doing_regs = 0;
}
}
/* Invoke the closure. */
(closure->fun) (cif,
cif->rtype->type == FFI_TYPE_STRUCT
/* The caller allocated space for the return
structure, and passed a pointer to this space in
R9. */
? struct_ret
/* We take advantage of being able to ignore that
the high part isn't set if the return value is
not in R10:R11, but in R10 only. */
: (void *) &llret,
avalue, closure->user_data);
return llret;
}
/* API function: Prepare the trampoline. */
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif *, void *, void **, void*),
void *user_data)
{
void *innerfn = ffi_prep_closure_inner;
FFI_ASSERT (cif->abi == FFI_SYSV);
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
memcpy (closure->tramp, ffi_cris_trampoline_template,
FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
&innerfn, sizeof (void *));
memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
&closure, sizeof (void *));
return FFI_OK;
}

View File

@@ -0,0 +1,50 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for CRIS.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#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_CRIS_TRAMPOLINE_CODE_PART_SIZE 36
#define FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE (7*4)
#define FFI_TRAMPOLINE_SIZE \
(FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE + FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE)
#define FFI_NATIVE_RAW_API 0
#endif

215
libffi/src/cris/sysv.S Normal file
View File

@@ -0,0 +1,215 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 2004 Simon Posnjak
Copyright (c) 2005 Axis Communications AB
CRIS 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.
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#include <ffi.h>
#define CONCAT(x,y) x ## y
#define XCONCAT(x,y) CONCAT (x, y)
#define L(x) XCONCAT (__USER_LABEL_PREFIX__, x)
.text
;; OK, when we get called we should have this (according to
;; AXIS ETRAX 100LX Programmer's Manual chapter 6.3).
;;
;; R10: ffi_prep_args (func. pointer)
;; R11: &ecif
;; R12: cif->bytes
;; R13: fig->flags
;; sp+0: ecif.rvalue
;; sp+4: fn (function pointer to the function that we need to call)
.globl L(ffi_call_SYSV)
.type L(ffi_call_SYSV),@function
.hidden L(ffi_call_SYSV)
L(ffi_call_SYSV):
;; Save the regs to the stack.
push $srp
;; Used for stack pointer saving.
push $r6
;; Used for function address pointer.
push $r7
;; Used for stack pointer saving.
push $r8
;; We save fig->flags to stack we will need them after we
;; call The Function.
push $r13
;; Saving current stack pointer.
move.d $sp,$r8
move.d $sp,$r6
;; Move address of ffi_prep_args to r13.
move.d $r10,$r13
;; Make room on the stack for the args of fn.
sub.d $r12,$sp
;; Function void ffi_prep_args(char *stack, extended_cif *ecif) parameters are:
;; r10 <-- stack pointer
;; r11 <-- &ecif (already there)
move.d $sp,$r10
;; Call the function.
jsr $r13
;; Save the size of the structures which are passed on stack.
move.d $r10,$r7
;; Move first four args in to r10..r13.
move.d [$sp+0],$r10
move.d [$sp+4],$r11
move.d [$sp+8],$r12
move.d [$sp+12],$r13
;; Adjust the stack and check if any parameters are given on stack.
addq 16,$sp
sub.d $r7,$r6
cmp.d $sp,$r6
bpl go_on
nop
go_on_no_params_on_stack:
move.d $r6,$sp
go_on:
;; Discover if we need to put rval address in to r9.
move.d [$r8+0],$r7
cmpq FFI_TYPE_STRUCT,$r7
bne call_now
nop
;; Move rval address to $r9.
move.d [$r8+20],$r9
call_now:
;; Move address of The Function in to r7.
move.d [$r8+24],$r7
;; Call The Function.
jsr $r7
;; Reset stack.
move.d $r8,$sp
;; Load rval type (fig->flags) in to r13.
pop $r13
;; Detect rval type.
cmpq FFI_TYPE_VOID,$r13
beq epilogue
cmpq FFI_TYPE_STRUCT,$r13
beq epilogue
cmpq FFI_TYPE_DOUBLE,$r13
beq return_double_or_longlong
cmpq FFI_TYPE_UINT64,$r13
beq return_double_or_longlong
cmpq FFI_TYPE_SINT64,$r13
beq return_double_or_longlong
nop
;; Just return the 32 bit value.
ba return
nop
return_double_or_longlong:
;; Load half of the rval to r10 and the other half to r11.
move.d [$sp+16],$r13
move.d $r10,[$r13]
addq 4,$r13
move.d $r11,[$r13]
ba epilogue
nop
return:
;; Load the rval to r10.
move.d [$sp+16],$r13
move.d $r10,[$r13]
epilogue:
pop $r8
pop $r7
pop $r6
Jump [$sp+]
.size ffi_call_SYSV,.-ffi_call_SYSV
/* Save R10..R13 into an array, somewhat like varargs. Copy the next
argument too, to simplify handling of any straddling parameter.
Save R9 and SP after those. Jump to function handling the rest.
Since this is a template, copied and the main function filled in by
the user. */
.globl L(ffi_cris_trampoline_template)
.type L(ffi_cris_trampoline_template),@function
.hidden L(ffi_cris_trampoline_template)
L(ffi_cris_trampoline_template):
0:
/* The value we get for "PC" is right after the prefix instruction,
two bytes from the beginning, i.e. 0b+2. */
move.d $r10,[$pc+2f-(0b+2)]
move.d $pc,$r10
1:
addq 2f-1b+4,$r10
move.d $r11,[$r10+]
move.d $r12,[$r10+]
move.d $r13,[$r10+]
move.d [$sp],$r11
move.d $r11,[$r10+]
move.d $r9,[$r10+]
move.d $sp,[$r10+]
subq FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE,$r10
move.d 0,$r11
3:
jump 0
2:
.size ffi_cris_trampoline_template,.-0b
/* This macro create a constant usable as "extern const int \name" in
C from within libffi, when \name has no prefix decoration. */
.macro const name,value
.globl \name
.type \name,@object
.hidden \name
\name:
.dword \value
.size \name,4
.endm
/* Constants for offsets within the trampoline. We could do this with
just symbols, avoiding memory contents and memory accesses, but the
C usage code would look a bit stranger. */
const L(ffi_cris_trampoline_fn_offset),2b-4-0b
const L(ffi_cris_trampoline_closure_offset),3b-4-0b

58
libffi/src/debug.c Normal file
View File

@@ -0,0 +1,58 @@
/* -----------------------------------------------------------------------
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
``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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <stdio.h>
/* General debugging routines */
void ffi_stop_here(void)
{
/* This function is only useful for debugging purposes.
Place a breakpoint on ffi_stop_here to be notified of
significant events. */
}
/* This function should only be called via the FFI_ASSERT() macro */
void ffi_assert(char *expr, char *file, int line)
{
fprintf(stderr, "ASSERTION FAILURE: %s at %s:%d\n", expr, file, line);
ffi_stop_here();
abort();
}
/* Perform a sanity check on an ffi_type structure */
void ffi_type_test(ffi_type *a, char *file, int line)
{
FFI_ASSERT_AT(a != NULL, file, line);
FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line);
FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line);
FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line);
FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line);
}

130
libffi/src/frv/eabi.S Normal file
View File

@@ -0,0 +1,130 @@
/* -----------------------------------------------------------------------
eabi.S - Copyright (c) 2004 Anthony Green
FR-V Assembly glue.
$Id: eabi.S,v 1.2 2008/01/29 12:28:14 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
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.
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.globl ffi_prep_args_EABI
.text
.p2align 4
.globl ffi_call_EABI
.type ffi_call_EABI, @function
# gr8 : ffi_prep_args
# gr9 : &ecif
# gr10: cif->bytes
# gr11: fig->flags
# gr12: ecif.rvalue
# gr13: fn
ffi_call_EABI:
addi sp, #-80, sp
sti fp, @(sp, #24)
addi sp, #24, fp
movsg lr, gr5
/* Make room for the new arguments. */
/* subi sp, fp, gr10 */
/* Store return address and incoming args on stack. */
sti gr5, @(fp, #8)
sti gr8, @(fp, #-4)
sti gr9, @(fp, #-8)
sti gr10, @(fp, #-12)
sti gr11, @(fp, #-16)
sti gr12, @(fp, #-20)
sti gr13, @(fp, #-24)
sub sp, gr10, sp
/* Call ffi_prep_args. */
ldi @(fp, #-4), gr4
addi sp, #0, gr8
ldi @(fp, #-8), gr9
#ifdef __FRV_FDPIC__
ldd @(gr4, gr0), gr14
calll @(gr14, gr0)
#else
calll @(gr4, gr0)
#endif
/* ffi_prep_args returns the new stack pointer. */
mov gr8, gr4
ldi @(sp, #0), gr8
ldi @(sp, #4), gr9
ldi @(sp, #8), gr10
ldi @(sp, #12), gr11
ldi @(sp, #16), gr12
ldi @(sp, #20), gr13
/* Always copy the return value pointer into the hidden
parameter register. This is only strictly necessary
when we're returning an aggregate type, but it doesn't
hurt to do this all the time, and it saves a branch. */
ldi @(fp, #-20), gr3
/* Use the ffi_prep_args return value for the new sp. */
mov gr4, sp
/* Call the target function. */
ldi @(fp, -24), gr4
#ifdef __FRV_FDPIC__
ldd @(gr4, gr0), gr14
calll @(gr14, gr0)
#else
calll @(gr4, gr0)
#endif
/* Store the result. */
ldi @(fp, #-16), gr10 /* fig->flags */
ldi @(fp, #-20), gr4 /* ecif.rvalue */
/* Is the return value stored in two registers? */
cmpi gr10, #8, icc0
bne icc0, 0, .L2
/* Yes, save them. */
sti gr8, @(gr4, #0)
sti gr9, @(gr4, #4)
bra .L3
.L2:
/* Is the return value a structure? */
cmpi gr10, #-1, icc0
beq icc0, 0, .L3
/* No, save a 4 byte return value. */
sti gr8, @(gr4, #0)
.L3:
/* Restore the stack, and return. */
ldi @(fp, 8), gr5
ld @(fp, gr0), fp
addi sp,#80,sp
jmpl @(gr5,gr0)
.size ffi_call_EABI, .-ffi_call_EABI

287
libffi/src/frv/ffi.c Normal file
View File

@@ -0,0 +1,287 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2004 Anthony Green
FR-V 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* 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)
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
register int count = 0;
p_argv = ecif->avalue;
argp = stack;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
(i != 0);
i--, p_arg++)
{
size_t z;
z = (*p_arg)->size;
if ((*p_arg)->type == FFI_TYPE_STRUCT)
{
z = sizeof(void*);
*(void **) argp = *p_argv;
}
/* if ((*p_arg)->type == FFI_TYPE_FLOAT)
{
if (count > 24)
{
// This is going on the stack. Turn it into a double.
*(double *) argp = (double) *(float*)(* p_argv);
z = sizeof(double);
}
else
*(void **) argp = *(void **)(* p_argv);
} */
else 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);
break;
default:
FFI_ASSERT(0);
}
}
else if (z == sizeof(int))
{
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
}
else
{
memcpy(argp, *p_argv, z);
}
p_argv++;
argp += z;
count += z;
}
return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
if (cif->rtype->type == FFI_TYPE_STRUCT)
cif->flags = -1;
else
cif->flags = cif->rtype->size;
cif->bytes = ALIGN (cif->bytes, 8);
return FFI_OK;
}
extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
extended_cif *,
unsigned, unsigned,
unsigned *,
void (*fn)());
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_EABI:
ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
default:
FFI_ASSERT(0);
break;
}
}
void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
unsigned arg4, unsigned arg5, unsigned arg6)
{
/* This function is called by a trampoline. The trampoline stows a
pointer to the ffi_closure object in gr7. We must save this
pointer in a place that will persist while we do our work. */
register ffi_closure *creg __asm__ ("gr7");
ffi_closure *closure = creg;
/* Arguments that don't fit in registers are found on the stack
at a fixed offset above the current frame pointer. */
register char *frame_pointer __asm__ ("fp");
char *stack_args = frame_pointer + 16;
/* Lay the register arguments down in a continuous chunk of memory. */
unsigned register_args[6] =
{ arg1, arg2, arg3, arg4, arg5, arg6 };
ffi_cif *cif = closure->cif;
ffi_type **arg_types = cif->arg_types;
void **avalue = alloca (cif->nargs * sizeof(void *));
char *ptr = (char *) register_args;
int i;
/* Find the address of each argument. */
for (i = 0; i < cif->nargs; i++)
{
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
avalue[i] = ptr + 3;
break;
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
avalue[i] = ptr + 2;
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_FLOAT:
avalue[i] = ptr;
break;
case FFI_TYPE_STRUCT:
avalue[i] = *(void**)ptr;
break;
default:
/* This is an 8-byte value. */
avalue[i] = ptr;
ptr += 4;
break;
}
ptr += 4;
/* If we've handled more arguments than fit in registers,
start looking at the those passed on the stack. */
if (ptr == ((char *)register_args + (6*4)))
ptr = stack_args;
}
/* Invoke the closure. */
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
/* The caller allocates space for the return structure, and
passes a pointer to this space in gr3. Use this value directly
as the return value. */
register void *return_struct_ptr __asm__("gr3");
(closure->fun) (cif, return_struct_ptr, avalue, closure->user_data);
}
else
{
/* Allocate space for the return value and call the function. */
long long rvalue;
(closure->fun) (cif, &rvalue, avalue, closure->user_data);
/* Functions return 4-byte or smaller results in gr8. 8-byte
values also use gr9. We fill the both, even for small return
values, just to avoid a branch. */
asm ("ldi @(%0, #0), gr8" : : "r" (&rvalue));
asm ("ldi @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1]));
}
}
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
unsigned long fn = (long) ffi_closure_eabi;
unsigned long cls = (long) closure;
#ifdef __FRV_FDPIC__
register void *got __asm__("gr15");
#endif
int i;
fn = (unsigned long) ffi_closure_eabi;
#ifdef __FRV_FDPIC__
tramp[0] = &tramp[2];
tramp[1] = got;
tramp[2] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */
tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */
tramp[4] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */
tramp[5] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */
tramp[6] = 0x9cc86000; /* ldi @(gr6, #0), gr14 */
tramp[7] = 0x8030e000; /* jmpl @(gr14, gr0) */
#else
tramp[0] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */
tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */
tramp[2] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */
tramp[3] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */
tramp[4] = 0x80300006; /* jmpl @(gr0, gr6) */
#endif
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* Cache flushing. */
for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
__asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (tramp), "r" (i));
return FFI_OK;
}

View File

@@ -0,0 +1,60 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2004 Red Hat, Inc.
Target configuration macros for FR-V
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- System specific configurations ----------------------------------- */
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
#ifdef FRV
FFI_EABI,
FFI_DEFAULT_ABI = FFI_EABI,
#endif
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
#ifdef __FRV_FDPIC__
/* Trampolines are 8 4-byte instructions long. */
#define FFI_TRAMPOLINE_SIZE (8*4)
#else
/* Trampolines are 5 4-byte instructions long. */
#define FFI_TRAMPOLINE_SIZE (5*4)
#endif
#endif

578
libffi/src/ia64/ffi.c Normal file
View File

@@ -0,0 +1,578 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Red Hat, Inc.
Copyright (c) 2000 Hewlett Packard Company
IA64 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <stdbool.h>
#include <float.h>
#include "ia64_flags.h"
/* A 64-bit pointer value. In LP64 mode, this is effectively a plain
pointer. In ILP32 mode, it's a pointer that's been extended to
64 bits by "addp4". */
typedef void *PTR64 __attribute__((mode(DI)));
/* Memory image of fp register contents. This is the implementation
specific format used by ldf.fill/stf.spill. All we care about is
that it wants a 16 byte aligned slot. */
typedef struct
{
UINT64 x[2] __attribute__((aligned(16)));
} fpreg;
/* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */
struct ia64_args
{
fpreg fp_regs[8]; /* Contents of 8 fp arg registers. */
UINT64 gp_regs[8]; /* Contents of 8 gp arg registers. */
UINT64 other_args[]; /* Arguments passed on stack, variable size. */
};
/* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */
static inline void *
endian_adjust (void *addr, size_t len)
{
#ifdef __BIG_ENDIAN__
return addr + (8 - len);
#else
return addr;
#endif
}
/* Store VALUE to ADDR in the current cpu implementation's fp spill format.
This is a macro instead of a function, so that it works for all 3 floating
point types without type conversions. Type conversion to long double breaks
the denorm support. */
#define stf_spill(addr, value) \
asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
/* Load a value from ADDR, which is in the current cpu implementation's
fp spill format. As above, this must also be a macro. */
#define ldf_fill(result, addr) \
asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
/* Return the size of the C type associated with with TYPE. Which will
be one of the FFI_IA64_TYPE_HFA_* values. */
static size_t
hfa_type_size (int type)
{
switch (type)
{
case FFI_IA64_TYPE_HFA_FLOAT:
return sizeof(float);
case FFI_IA64_TYPE_HFA_DOUBLE:
return sizeof(double);
case FFI_IA64_TYPE_HFA_LDOUBLE:
return sizeof(__float80);
default:
abort ();
}
}
/* Load from ADDR a value indicated by TYPE. Which will be one of
the FFI_IA64_TYPE_HFA_* values. */
static void
hfa_type_load (fpreg *fpaddr, int type, void *addr)
{
switch (type)
{
case FFI_IA64_TYPE_HFA_FLOAT:
stf_spill (fpaddr, *(float *) addr);
return;
case FFI_IA64_TYPE_HFA_DOUBLE:
stf_spill (fpaddr, *(double *) addr);
return;
case FFI_IA64_TYPE_HFA_LDOUBLE:
stf_spill (fpaddr, *(__float80 *) addr);
return;
default:
abort ();
}
}
/* Load VALUE into ADDR as indicated by TYPE. Which will be one of
the FFI_IA64_TYPE_HFA_* values. */
static void
hfa_type_store (int type, void *addr, fpreg *fpaddr)
{
switch (type)
{
case FFI_IA64_TYPE_HFA_FLOAT:
{
float result;
ldf_fill (result, fpaddr);
*(float *) addr = result;
break;
}
case FFI_IA64_TYPE_HFA_DOUBLE:
{
double result;
ldf_fill (result, fpaddr);
*(double *) addr = result;
break;
}
case FFI_IA64_TYPE_HFA_LDOUBLE:
{
__float80 result;
ldf_fill (result, fpaddr);
*(__float80 *) addr = result;
break;
}
default:
abort ();
}
}
/* Is TYPE a struct containing floats, doubles, or extended doubles,
all of the same fp type? If so, return the element type. Return
FFI_TYPE_VOID if not. */
static int
hfa_element_type (ffi_type *type, int nested)
{
int element = FFI_TYPE_VOID;
switch (type->type)
{
case FFI_TYPE_FLOAT:
/* We want to return VOID for raw floating-point types, but the
synthetic HFA type if we're nested within an aggregate. */
if (nested)
element = FFI_IA64_TYPE_HFA_FLOAT;
break;
case FFI_TYPE_DOUBLE:
/* Similarly. */
if (nested)
element = FFI_IA64_TYPE_HFA_DOUBLE;
break;
case FFI_TYPE_LONGDOUBLE:
/* Similarly, except that that HFA is true for double extended,
but not quad precision. Both have sizeof == 16, so tell the
difference based on the precision. */
if (LDBL_MANT_DIG == 64 && nested)
element = FFI_IA64_TYPE_HFA_LDOUBLE;
break;
case FFI_TYPE_STRUCT:
{
ffi_type **ptr = &type->elements[0];
for (ptr = &type->elements[0]; *ptr ; ptr++)
{
int sub_element = hfa_element_type (*ptr, 1);
if (sub_element == FFI_TYPE_VOID)
return FFI_TYPE_VOID;
if (element == FFI_TYPE_VOID)
element = sub_element;
else if (element != sub_element)
return FFI_TYPE_VOID;
}
}
break;
default:
return FFI_TYPE_VOID;
}
return element;
}
/* Perform machine dependent cif processing. */
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
int flags;
/* Adjust cif->bytes to include space for the bits of the ia64_args frame
that preceeds the integer register portion. The estimate that the
generic bits did for the argument space required is good enough for the
integer component. */
cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
if (cif->bytes < sizeof(struct ia64_args))
cif->bytes = sizeof(struct ia64_args);
/* Set the return type flag. */
flags = cif->rtype->type;
switch (cif->rtype->type)
{
case FFI_TYPE_LONGDOUBLE:
/* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
and encode quad precision as a two-word integer structure. */
if (LDBL_MANT_DIG != 64)
flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
break;
case FFI_TYPE_STRUCT:
{
size_t size = cif->rtype->size;
int hfa_type = hfa_element_type (cif->rtype, 0);
if (hfa_type != FFI_TYPE_VOID)
{
size_t nelts = size / hfa_type_size (hfa_type);
if (nelts <= 8)
flags = hfa_type | (size << 8);
}
else
{
if (size <= 32)
flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
}
}
break;
default:
break;
}
cif->flags = flags;
return FFI_OK;
}
extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(), UINT64);
void
ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{
struct ia64_args *stack;
long i, avn, gpcount, fpcount;
ffi_type **p_arg;
FFI_ASSERT (cif->abi == FFI_UNIX);
/* If we have no spot for a return value, make one. */
if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
rvalue = alloca (cif->rtype->size);
/* Allocate the stack frame. */
stack = alloca (cif->bytes);
gpcount = fpcount = 0;
avn = cif->nargs;
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
{
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
break;
case FFI_TYPE_UINT8:
stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
break;
case FFI_TYPE_SINT16:
stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
break;
case FFI_TYPE_UINT16:
stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
break;
case FFI_TYPE_SINT32:
stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
break;
case FFI_TYPE_UINT32:
stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
break;
case FFI_TYPE_POINTER:
stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
break;
case FFI_TYPE_FLOAT:
if (gpcount < 8 && fpcount < 8)
stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
break;
case FFI_TYPE_DOUBLE:
if (gpcount < 8 && fpcount < 8)
stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
break;
case FFI_TYPE_LONGDOUBLE:
if (gpcount & 1)
gpcount++;
if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
gpcount += 2;
break;
case FFI_TYPE_STRUCT:
{
size_t size = (*p_arg)->size;
size_t align = (*p_arg)->alignment;
int hfa_type = hfa_element_type (*p_arg, 0);
FFI_ASSERT (align <= 16);
if (align == 16 && (gpcount & 1))
gpcount++;
if (hfa_type != FFI_TYPE_VOID)
{
size_t hfa_size = hfa_type_size (hfa_type);
size_t offset = 0;
size_t gp_offset = gpcount * 8;
while (fpcount < 8
&& offset < size
&& gp_offset < 8 * 8)
{
hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
avalue[i] + offset);
offset += hfa_size;
gp_offset += hfa_size;
fpcount += 1;
}
}
memcpy (&stack->gp_regs[gpcount], avalue[i], size);
gpcount += (size + 7) / 8;
}
break;
default:
abort ();
}
}
ffi_call_unix (stack, rvalue, fn, cif->flags);
}
/* Closures represent a pair consisting of a function pointer, and
some user data. A closure is invoked by reinterpreting the closure
as a function pointer, and branching to it. Thus we can make an
interpreted function callable as a C function: We turn the
interpreter itself, together with a pointer specifying the
interpreted procedure, into a closure.
For IA64, function pointer are already pairs consisting of a code
pointer, and a gp pointer. The latter is needed to access global
variables. Here we set up such a pair as the first two words of
the closure (in the "trampoline" area), but we replace the gp
pointer with a pointer to the closure itself. We also add the real
gp pointer to the closure. This allows the function entry code to
both retrieve the user data, and to restire the correct gp pointer. */
extern void ffi_closure_unix ();
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
/* The layout of a function descriptor. A C function pointer really
points to one of these. */
struct ia64_fd
{
UINT64 code_pointer;
UINT64 gp;
};
struct ffi_ia64_trampoline_struct
{
UINT64 code_pointer; /* Pointer to ffi_closure_unix. */
UINT64 fake_gp; /* Pointer to closure, installed as gp. */
UINT64 real_gp; /* Real gp value. */
};
struct ffi_ia64_trampoline_struct *tramp;
struct ia64_fd *fd;
FFI_ASSERT (cif->abi == FFI_UNIX);
tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
fd = (struct ia64_fd *)(void *)ffi_closure_unix;
tramp->code_pointer = fd->code_pointer;
tramp->real_gp = fd->gp;
tramp->fake_gp = (UINT64)(PTR64)closure;
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
UINT64
ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
void *rvalue, void *r8)
{
ffi_cif *cif;
void **avalue;
ffi_type **p_arg;
long i, avn, gpcount, fpcount;
cif = closure->cif;
avn = cif->nargs;
avalue = alloca (avn * sizeof (void *));
/* If the structure return value is passed in memory get that location
from r8 so as to pass the value directly back to the caller. */
if (cif->flags == FFI_TYPE_STRUCT)
rvalue = r8;
gpcount = fpcount = 0;
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
{
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
break;
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
avalue[i] = &stack->gp_regs[gpcount++];
break;
case FFI_TYPE_POINTER:
avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
break;
case FFI_TYPE_FLOAT:
if (gpcount < 8 && fpcount < 8)
{
fpreg *addr = &stack->fp_regs[fpcount++];
float result;
avalue[i] = addr;
ldf_fill (result, addr);
*(float *)addr = result;
}
else
avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
gpcount++;
break;
case FFI_TYPE_DOUBLE:
if (gpcount < 8 && fpcount < 8)
{
fpreg *addr = &stack->fp_regs[fpcount++];
double result;
avalue[i] = addr;
ldf_fill (result, addr);
*(double *)addr = result;
}
else
avalue[i] = &stack->gp_regs[gpcount];
gpcount++;
break;
case FFI_TYPE_LONGDOUBLE:
if (gpcount & 1)
gpcount++;
if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
{
fpreg *addr = &stack->fp_regs[fpcount++];
__float80 result;
avalue[i] = addr;
ldf_fill (result, addr);
*(__float80 *)addr = result;
}
else
avalue[i] = &stack->gp_regs[gpcount];
gpcount += 2;
break;
case FFI_TYPE_STRUCT:
{
size_t size = (*p_arg)->size;
size_t align = (*p_arg)->alignment;
int hfa_type = hfa_element_type (*p_arg, 0);
FFI_ASSERT (align <= 16);
if (align == 16 && (gpcount & 1))
gpcount++;
if (hfa_type != FFI_TYPE_VOID)
{
size_t hfa_size = hfa_type_size (hfa_type);
size_t offset = 0;
size_t gp_offset = gpcount * 8;
void *addr = alloca (size);
avalue[i] = addr;
while (fpcount < 8
&& offset < size
&& gp_offset < 8 * 8)
{
hfa_type_store (hfa_type, addr + offset,
&stack->fp_regs[fpcount]);
offset += hfa_size;
gp_offset += hfa_size;
fpcount += 1;
}
if (offset < size)
memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
size - offset);
}
else
avalue[i] = &stack->gp_regs[gpcount];
gpcount += (size + 7) / 8;
}
break;
default:
abort ();
}
}
closure->fun (cif, rvalue, avalue, closure->user_data);
return cif->flags;
}

View File

@@ -0,0 +1,49 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for IA-64.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#ifndef LIBFFI_ASM
typedef unsigned long long ffi_arg;
typedef signed long long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
FFI_UNIX, /* Linux and all Unix variants use the same conventions */
FFI_DEFAULT_ABI = FFI_UNIX,
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
/* can be interpreted as a C function */
/* descriptor: */
#endif

View File

@@ -0,0 +1,39 @@
/* -----------------------------------------------------------------------
ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company
IA64/unix Foreign Function Interface
Original author: Hans Boehm, HP Labs
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.
----------------------------------------------------------------------- */
/* "Type" codes used between assembly and C. When used as a part of
a cfi->flags value, the low byte will be these extra type codes,
and bits 8-31 will be the actual size of the type. */
/* Small structures containing N words in integer registers. */
#define FFI_IA64_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 1)
/* Homogeneous Floating Point Aggregates (HFAs) which are returned
in FP registers. */
#define FFI_IA64_TYPE_HFA_FLOAT (FFI_TYPE_LAST + 2)
#define FFI_IA64_TYPE_HFA_DOUBLE (FFI_TYPE_LAST + 3)
#define FFI_IA64_TYPE_HFA_LDOUBLE (FFI_TYPE_LAST + 4)

555
libffi/src/ia64/unix.S Normal file
View File

@@ -0,0 +1,555 @@
/* -----------------------------------------------------------------------
unix.S - Copyright (c) 1998 Red Hat, Inc.
Copyright (c) 2000 Hewlett Packard Company
IA64/unix Foreign Function Interface
Primary author: Hans Boehm, HP Labs
Loosely modeled on Cygnus code for other platforms.
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 <fficonfig.h>
#include <ffi.h>
#include "ia64_flags.h"
.pred.safe_across_calls p1-p5,p16-p63
.text
/* int ffi_call_unix (struct ia64_args *stack, PTR64 rvalue,
void (*fn)(), int flags);
*/
.align 16
.global ffi_call_unix
.proc ffi_call_unix
ffi_call_unix:
.prologue
/* Bit o trickiness. We actually share a stack frame with ffi_call.
Rely on the fact that ffi_call uses a vframe and don't bother
tracking one here at all. */
.fframe 0
.save ar.pfs, r36 // loc0
alloc loc0 = ar.pfs, 4, 3, 8, 0
.save rp, loc1
mov loc1 = b0
.body
add r16 = 16, in0
mov loc2 = gp
mov r8 = in1
;;
/* Load up all of the argument registers. */
ldf.fill f8 = [in0], 32
ldf.fill f9 = [r16], 32
;;
ldf.fill f10 = [in0], 32
ldf.fill f11 = [r16], 32
;;
ldf.fill f12 = [in0], 32
ldf.fill f13 = [r16], 32
;;
ldf.fill f14 = [in0], 32
ldf.fill f15 = [r16], 24
;;
ld8 out0 = [in0], 16
ld8 out1 = [r16], 16
;;
ld8 out2 = [in0], 16
ld8 out3 = [r16], 16
;;
ld8 out4 = [in0], 16
ld8 out5 = [r16], 16
;;
ld8 out6 = [in0]
ld8 out7 = [r16]
;;
/* Deallocate the register save area from the stack frame. */
mov sp = in0
/* Call the target function. */
ld8 r16 = [in2], 8
;;
ld8 gp = [in2]
mov b6 = r16
br.call.sptk.many b0 = b6
;;
/* Dispatch to handle return value. */
mov gp = loc2
zxt1 r16 = in3
;;
mov ar.pfs = loc0
addl r18 = @ltoffx(.Lst_table), gp
;;
ld8.mov r18 = [r18], .Lst_table
mov b0 = loc1
;;
shladd r18 = r16, 3, r18
;;
ld8 r17 = [r18]
shr in3 = in3, 8
;;
add r17 = r17, r18
;;
mov b6 = r17
br b6
;;
.Lst_void:
br.ret.sptk.many b0
;;
.Lst_uint8:
zxt1 r8 = r8
;;
st8 [in1] = r8
br.ret.sptk.many b0
;;
.Lst_sint8:
sxt1 r8 = r8
;;
st8 [in1] = r8
br.ret.sptk.many b0
;;
.Lst_uint16:
zxt2 r8 = r8
;;
st8 [in1] = r8
br.ret.sptk.many b0
;;
.Lst_sint16:
sxt2 r8 = r8
;;
st8 [in1] = r8
br.ret.sptk.many b0
;;
.Lst_uint32:
zxt4 r8 = r8
;;
st8 [in1] = r8
br.ret.sptk.many b0
;;
.Lst_sint32:
sxt4 r8 = r8
;;
st8 [in1] = r8
br.ret.sptk.many b0
;;
.Lst_int64:
st8 [in1] = r8
br.ret.sptk.many b0
;;
.Lst_float:
stfs [in1] = f8
br.ret.sptk.many b0
;;
.Lst_double:
stfd [in1] = f8
br.ret.sptk.many b0
;;
.Lst_ldouble:
stfe [in1] = f8
br.ret.sptk.many b0
;;
.Lst_small_struct:
add sp = -16, sp
cmp.lt p6, p0 = 8, in3
cmp.lt p7, p0 = 16, in3
cmp.lt p8, p0 = 24, in3
;;
add r16 = 8, sp
add r17 = 16, sp
add r18 = 24, sp
;;
st8 [sp] = r8
(p6) st8 [r16] = r9
mov out0 = in1
(p7) st8 [r17] = r10
(p8) st8 [r18] = r11
mov out1 = sp
mov out2 = in3
br.call.sptk.many b0 = memcpy#
;;
mov ar.pfs = loc0
mov b0 = loc1
mov gp = loc2
br.ret.sptk.many b0
.Lst_hfa_float:
add r16 = 4, in1
cmp.lt p6, p0 = 4, in3
;;
stfs [in1] = f8, 8
(p6) stfs [r16] = f9, 8
cmp.lt p7, p0 = 8, in3
cmp.lt p8, p0 = 12, in3
;;
(p7) stfs [in1] = f10, 8
(p8) stfs [r16] = f11, 8
cmp.lt p9, p0 = 16, in3
cmp.lt p10, p0 = 20, in3
;;
(p9) stfs [in1] = f12, 8
(p10) stfs [r16] = f13, 8
cmp.lt p6, p0 = 24, in3
cmp.lt p7, p0 = 28, in3
;;
(p6) stfs [in1] = f14
(p7) stfs [r16] = f15
br.ret.sptk.many b0
;;
.Lst_hfa_double:
add r16 = 8, in1
cmp.lt p6, p0 = 8, in3
;;
stfd [in1] = f8, 16
(p6) stfd [r16] = f9, 16
cmp.lt p7, p0 = 16, in3
cmp.lt p8, p0 = 24, in3
;;
(p7) stfd [in1] = f10, 16
(p8) stfd [r16] = f11, 16
cmp.lt p9, p0 = 32, in3
cmp.lt p10, p0 = 40, in3
;;
(p9) stfd [in1] = f12, 16
(p10) stfd [r16] = f13, 16
cmp.lt p6, p0 = 48, in3
cmp.lt p7, p0 = 56, in3
;;
(p6) stfd [in1] = f14
(p7) stfd [r16] = f15
br.ret.sptk.many b0
;;
.Lst_hfa_ldouble:
add r16 = 16, in1
cmp.lt p6, p0 = 16, in3
;;
stfe [in1] = f8, 32
(p6) stfe [r16] = f9, 32
cmp.lt p7, p0 = 32, in3
cmp.lt p8, p0 = 48, in3
;;
(p7) stfe [in1] = f10, 32
(p8) stfe [r16] = f11, 32
cmp.lt p9, p0 = 64, in3
cmp.lt p10, p0 = 80, in3
;;
(p9) stfe [in1] = f12, 32
(p10) stfe [r16] = f13, 32
cmp.lt p6, p0 = 96, in3
cmp.lt p7, p0 = 112, in3
;;
(p6) stfe [in1] = f14
(p7) stfe [r16] = f15
br.ret.sptk.many b0
;;
.endp ffi_call_unix
.align 16
.global ffi_closure_unix
.proc ffi_closure_unix
#define FRAME_SIZE (8*16 + 8*8 + 8*16)
ffi_closure_unix:
.prologue
.save ar.pfs, r40 // loc0
alloc loc0 = ar.pfs, 8, 4, 4, 0
.fframe FRAME_SIZE
add r12 = -FRAME_SIZE, r12
.save rp, loc1
mov loc1 = b0
.save ar.unat, loc2
mov loc2 = ar.unat
.body
/* Retrieve closure pointer and real gp. */
#ifdef _ILP32
addp4 out0 = 0, gp
addp4 gp = 16, gp
#else
mov out0 = gp
add gp = 16, gp
#endif
;;
ld8 gp = [gp]
/* Spill all of the possible argument registers. */
add r16 = 16 + 8*16, sp
add r17 = 16 + 8*16 + 16, sp
;;
stf.spill [r16] = f8, 32
stf.spill [r17] = f9, 32
mov loc3 = gp
;;
stf.spill [r16] = f10, 32
stf.spill [r17] = f11, 32
;;
stf.spill [r16] = f12, 32
stf.spill [r17] = f13, 32
;;
stf.spill [r16] = f14, 32
stf.spill [r17] = f15, 24
;;
.mem.offset 0, 0
st8.spill [r16] = in0, 16
.mem.offset 8, 0
st8.spill [r17] = in1, 16
add out1 = 16 + 8*16, sp
;;
.mem.offset 0, 0
st8.spill [r16] = in2, 16
.mem.offset 8, 0
st8.spill [r17] = in3, 16
add out2 = 16, sp
;;
.mem.offset 0, 0
st8.spill [r16] = in4, 16
.mem.offset 8, 0
st8.spill [r17] = in5, 16
mov out3 = r8
;;
.mem.offset 0, 0
st8.spill [r16] = in6
.mem.offset 8, 0
st8.spill [r17] = in7
/* Invoke ffi_closure_unix_inner for the hard work. */
br.call.sptk.many b0 = ffi_closure_unix_inner
;;
/* Dispatch to handle return value. */
mov gp = loc3
zxt1 r16 = r8
;;
addl r18 = @ltoffx(.Lld_table), gp
mov ar.pfs = loc0
;;
ld8.mov r18 = [r18], .Lld_table
mov b0 = loc1
;;
shladd r18 = r16, 3, r18
mov ar.unat = loc2
;;
ld8 r17 = [r18]
shr r8 = r8, 8
;;
add r17 = r17, r18
add r16 = 16, sp
;;
mov b6 = r17
br b6
;;
.label_state 1
.Lld_void:
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_int:
.body
.copy_state 1
ld8 r8 = [r16]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_float:
.body
.copy_state 1
ldfs f8 = [r16]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_double:
.body
.copy_state 1
ldfd f8 = [r16]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_ldouble:
.body
.copy_state 1
ldfe f8 = [r16]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_small_struct:
.body
.copy_state 1
add r17 = 8, r16
cmp.lt p6, p0 = 8, r8
cmp.lt p7, p0 = 16, r8
cmp.lt p8, p0 = 24, r8
;;
ld8 r8 = [r16], 16
(p6) ld8 r9 = [r17], 16
;;
(p7) ld8 r10 = [r16]
(p8) ld8 r11 = [r17]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_hfa_float:
.body
.copy_state 1
add r17 = 4, r16
cmp.lt p6, p0 = 4, r8
;;
ldfs f8 = [r16], 8
(p6) ldfs f9 = [r17], 8
cmp.lt p7, p0 = 8, r8
cmp.lt p8, p0 = 12, r8
;;
(p7) ldfs f10 = [r16], 8
(p8) ldfs f11 = [r17], 8
cmp.lt p9, p0 = 16, r8
cmp.lt p10, p0 = 20, r8
;;
(p9) ldfs f12 = [r16], 8
(p10) ldfs f13 = [r17], 8
cmp.lt p6, p0 = 24, r8
cmp.lt p7, p0 = 28, r8
;;
(p6) ldfs f14 = [r16]
(p7) ldfs f15 = [r17]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_hfa_double:
.body
.copy_state 1
add r17 = 8, r16
cmp.lt p6, p0 = 8, r8
;;
ldfd f8 = [r16], 16
(p6) ldfd f9 = [r17], 16
cmp.lt p7, p0 = 16, r8
cmp.lt p8, p0 = 24, r8
;;
(p7) ldfd f10 = [r16], 16
(p8) ldfd f11 = [r17], 16
cmp.lt p9, p0 = 32, r8
cmp.lt p10, p0 = 40, r8
;;
(p9) ldfd f12 = [r16], 16
(p10) ldfd f13 = [r17], 16
cmp.lt p6, p0 = 48, r8
cmp.lt p7, p0 = 56, r8
;;
(p6) ldfd f14 = [r16]
(p7) ldfd f15 = [r17]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.Lld_hfa_ldouble:
.body
.copy_state 1
add r17 = 16, r16
cmp.lt p6, p0 = 16, r8
;;
ldfe f8 = [r16], 32
(p6) ldfe f9 = [r17], 32
cmp.lt p7, p0 = 32, r8
cmp.lt p8, p0 = 48, r8
;;
(p7) ldfe f10 = [r16], 32
(p8) ldfe f11 = [r17], 32
cmp.lt p9, p0 = 64, r8
cmp.lt p10, p0 = 80, r8
;;
(p9) ldfe f12 = [r16], 32
(p10) ldfe f13 = [r17], 32
cmp.lt p6, p0 = 96, r8
cmp.lt p7, p0 = 112, r8
;;
(p6) ldfe f14 = [r16]
(p7) ldfe f15 = [r17]
.restore sp
add sp = FRAME_SIZE, sp
br.ret.sptk.many b0
;;
.endp ffi_closure_unix
.section .rodata
.align 8
.Lst_table:
data8 @pcrel(.Lst_void) // FFI_TYPE_VOID
data8 @pcrel(.Lst_sint32) // FFI_TYPE_INT
data8 @pcrel(.Lst_float) // FFI_TYPE_FLOAT
data8 @pcrel(.Lst_double) // FFI_TYPE_DOUBLE
data8 @pcrel(.Lst_ldouble) // FFI_TYPE_LONGDOUBLE
data8 @pcrel(.Lst_uint8) // FFI_TYPE_UINT8
data8 @pcrel(.Lst_sint8) // FFI_TYPE_SINT8
data8 @pcrel(.Lst_uint16) // FFI_TYPE_UINT16
data8 @pcrel(.Lst_sint16) // FFI_TYPE_SINT16
data8 @pcrel(.Lst_uint32) // FFI_TYPE_UINT32
data8 @pcrel(.Lst_sint32) // FFI_TYPE_SINT32
data8 @pcrel(.Lst_int64) // FFI_TYPE_UINT64
data8 @pcrel(.Lst_int64) // FFI_TYPE_SINT64
data8 @pcrel(.Lst_void) // FFI_TYPE_STRUCT
data8 @pcrel(.Lst_int64) // FFI_TYPE_POINTER
data8 @pcrel(.Lst_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT
data8 @pcrel(.Lst_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT
data8 @pcrel(.Lst_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE
data8 @pcrel(.Lst_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE
.Lld_table:
data8 @pcrel(.Lld_void) // FFI_TYPE_VOID
data8 @pcrel(.Lld_int) // FFI_TYPE_INT
data8 @pcrel(.Lld_float) // FFI_TYPE_FLOAT
data8 @pcrel(.Lld_double) // FFI_TYPE_DOUBLE
data8 @pcrel(.Lld_ldouble) // FFI_TYPE_LONGDOUBLE
data8 @pcrel(.Lld_int) // FFI_TYPE_UINT8
data8 @pcrel(.Lld_int) // FFI_TYPE_SINT8
data8 @pcrel(.Lld_int) // FFI_TYPE_UINT16
data8 @pcrel(.Lld_int) // FFI_TYPE_SINT16
data8 @pcrel(.Lld_int) // FFI_TYPE_UINT32
data8 @pcrel(.Lld_int) // FFI_TYPE_SINT32
data8 @pcrel(.Lld_int) // FFI_TYPE_UINT64
data8 @pcrel(.Lld_int) // FFI_TYPE_SINT64
data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT
data8 @pcrel(.Lld_int) // FFI_TYPE_POINTER
data8 @pcrel(.Lld_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT
data8 @pcrel(.Lld_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT
data8 @pcrel(.Lld_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE
data8 @pcrel(.Lld_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE

337
libffi/src/java_raw_api.c Normal file
View File

@@ -0,0 +1,337 @@
/* -----------------------------------------------------------------------
java_raw_api.c - Copyright (c) 1999 Red Hat, Inc.
Cloned from raw_api.c
Raw_api.c author: Kresten Krab Thorup <krab@gnu.org>
Java_raw_api.c author: Hans-J. Boehm <hboehm@hpl.hp.com>
$Id $
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.
----------------------------------------------------------------------- */
/* This defines a Java- and 64-bit specific variant of the raw API. */
/* It assumes that "raw" argument blocks look like Java stacks on a */
/* 64-bit machine. Arguments that can be stored in a single stack */
/* stack slots (longs, doubles) occupy 128 bits, but only the first */
/* 64 bits are actually used. */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#if !defined(NO_JAVA_RAW_API) && !defined(FFI_NO_RAW_API)
size_t
ffi_java_raw_size (ffi_cif *cif)
{
size_t result = 0;
int i;
ffi_type **at = cif->arg_types;
for (i = cif->nargs-1; i >= 0; i--, at++)
{
switch((*at) -> type) {
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_DOUBLE:
result += 2 * FFI_SIZEOF_ARG;
break;
case FFI_TYPE_STRUCT:
/* No structure parameters in Java. */
abort();
default:
result += FFI_SIZEOF_ARG;
}
}
return result;
}
void
ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
{
unsigned i;
ffi_type **tp = cif->arg_types;
#if WORDS_BIGENDIAN
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
switch ((*tp)->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
*args = (void*) ((char*)(raw++) + 3);
break;
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
*args = (void*) ((char*)(raw++) + 2);
break;
#if FFI_SIZEOF_ARG == 8
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_DOUBLE:
*args = (void *)raw;
raw += 2;
break;
#endif
case FFI_TYPE_POINTER:
*args = (void*) &(raw++)->ptr;
break;
default:
*args = raw;
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
#else /* WORDS_BIGENDIAN */
#if !PDP
/* then assume little endian */
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
#if FFI_SIZEOF_ARG == 8
switch((*tp)->type) {
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_DOUBLE:
*args = (void*) raw;
raw += 2;
break;
default:
*args = (void*) raw++;
}
#else /* FFI_SIZEOF_ARG != 8 */
*args = (void*) raw;
raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
#endif /* FFI_SIZEOF_ARG == 8 */
}
#else
#error "pdp endian not supported"
#endif /* ! PDP */
#endif /* WORDS_BIGENDIAN */
}
void
ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
{
unsigned i;
ffi_type **tp = cif->arg_types;
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
switch ((*tp)->type)
{
case FFI_TYPE_UINT8:
#if WORDS_BIGENDIAN
*(UINT32*)(raw++) = *(UINT8*) (*args);
#else
(raw++)->uint = *(UINT8*) (*args);
#endif
break;
case FFI_TYPE_SINT8:
#if WORDS_BIGENDIAN
*(SINT32*)(raw++) = *(SINT8*) (*args);
#else
(raw++)->sint = *(SINT8*) (*args);
#endif
break;
case FFI_TYPE_UINT16:
#if WORDS_BIGENDIAN
*(UINT32*)(raw++) = *(UINT16*) (*args);
#else
(raw++)->uint = *(UINT16*) (*args);
#endif
break;
case FFI_TYPE_SINT16:
#if WORDS_BIGENDIAN
*(SINT32*)(raw++) = *(SINT16*) (*args);
#else
(raw++)->sint = *(SINT16*) (*args);
#endif
break;
case FFI_TYPE_UINT32:
#if WORDS_BIGENDIAN
*(UINT32*)(raw++) = *(UINT32*) (*args);
#else
(raw++)->uint = *(UINT32*) (*args);
#endif
break;
case FFI_TYPE_SINT32:
#if WORDS_BIGENDIAN
*(SINT32*)(raw++) = *(SINT32*) (*args);
#else
(raw++)->sint = *(SINT32*) (*args);
#endif
break;
case FFI_TYPE_FLOAT:
(raw++)->flt = *(FLOAT32*) (*args);
break;
#if FFI_SIZEOF_ARG == 8
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_DOUBLE:
raw->uint = *(UINT64*) (*args);
raw += 2;
break;
#endif
case FFI_TYPE_POINTER:
(raw++)->ptr = **(void***) args;
break;
default:
#if FFI_SIZEOF_ARG == 8
FFI_ASSERT(0); /* Should have covered all cases */
#else
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
#endif
}
}
}
#if !FFI_NATIVE_RAW_API
static void
ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue)
{
#if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8
switch (cif->rtype->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_UINT32:
*(UINT64 *)rvalue <<= 32;
break;
case FFI_TYPE_SINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_INT:
*(SINT64 *)rvalue <<= 32;
break;
default:
break;
}
#endif
}
static void
ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue)
{
#if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8
switch (cif->rtype->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_UINT32:
*(UINT64 *)rvalue >>= 32;
break;
case FFI_TYPE_SINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_INT:
*(SINT64 *)rvalue >>= 32;
break;
default:
break;
}
#endif
}
/* This is a generic definition of ffi_raw_call, to be used if the
* native system does not provide a machine-specific implementation.
* Having this, allows code to be written for the raw API, without
* the need for system-specific code to handle input in that format;
* these following couple of functions will handle the translation forth
* and back automatically. */
void ffi_java_raw_call (ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *raw)
{
void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
ffi_java_raw_to_ptrarray (cif, raw, avalue);
ffi_call (cif, fn, rvalue, avalue);
ffi_java_rvalue_to_raw (cif, rvalue);
}
#if FFI_CLOSURES /* base system provides closures */
static void
ffi_java_translate_args (ffi_cif *cif, void *rvalue,
void **avalue, void *user_data)
{
ffi_raw *raw = (ffi_raw*)alloca (ffi_java_raw_size (cif));
ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
ffi_java_ptrarray_to_raw (cif, avalue, raw);
(*cl->fun) (cif, rvalue, raw, cl->user_data);
ffi_java_raw_to_rvalue (cif, rvalue);
}
/* Again, here is the generic version of ffi_prep_raw_closure, which
* will install an intermediate "hub" for translation of arguments from
* the pointer-array format, to the raw format */
ffi_status
ffi_prep_java_raw_closure (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
{
ffi_status status;
status = ffi_prep_closure ((ffi_closure*) cl,
cif,
&ffi_java_translate_args,
(void*)cl);
if (status == FFI_OK)
{
cl->fun = fun;
cl->user_data = user_data;
}
return status;
}
#endif /* FFI_CLOSURES */
#endif /* !FFI_NATIVE_RAW_API */
#endif /* !FFI_NO_RAW_API */

231
libffi/src/m32r/ffi.c Normal file
View File

@@ -0,0 +1,231 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2004 Renesas Technology
M32R 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 RENESAS TECHNOLOGY 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>
/* 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)
{
unsigned int i;
int tmp;
unsigned int avn;
void **p_argv;
char *argp;
ffi_type **p_arg;
tmp = 0;
argp = stack;
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8)
{
*(void **) argp = ecif->rvalue;
argp += 4;
}
avn = ecif->cif->nargs;
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
(i != 0) && (avn != 0);
i--, p_arg++)
{
size_t z;
/* Align if necessary. */
if (((*p_arg)->alignment - 1) & (unsigned) argp)
argp = (char *) ALIGN (argp, (*p_arg)->alignment);
if (avn != 0)
{
avn--;
z = (*p_arg)->size;
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);
break;
case FFI_TYPE_STRUCT:
z = (*p_arg)->size;
if ((*p_arg)->alignment != 1)
memcpy (argp, *p_argv, z);
else
memcpy (argp + 4 - z, *p_argv, z);
z = sizeof (int);
break;
default:
FFI_ASSERT(0);
}
}
else if (z == sizeof (int))
{
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
}
else
{
if ((*p_arg)->type == FFI_TYPE_STRUCT)
{
if (z > 8)
{
*(unsigned int *) argp = (unsigned int)(void *)(* p_argv);
z = sizeof(void *);
}
else
{
memcpy(argp, *p_argv, z);
z = 8;
}
}
else
{
/* Double or long long 64bit. */
memcpy (argp, *p_argv, z);
}
}
p_argv++;
argp += z;
}
}
return;
}
/* Perform machine dependent cif processing. */
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Set the return type flag. */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_STRUCT:
if (cif->rtype->size <= 4)
cif->flags = FFI_TYPE_INT;
else if (cif->rtype->size <= 8)
cif->flags = FFI_TYPE_DOUBLE;
else
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_DOUBLE:
cif->flags = FFI_TYPE_DOUBLE;
break;
case FFI_TYPE_FLOAT:
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)());
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);
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
int size = cif->rtype->size;
int align = cif->rtype->alignment;
if (size < 4)
{
if (align == 1)
*(unsigned long *)(ecif.rvalue) <<= (4 - size) * 8;
}
else if (4 < size && size < 8)
{
if (align == 1)
{
memcpy (ecif.rvalue, ecif.rvalue + 8-size, size);
}
else if (align == 2)
{
if (size & 1)
size += 1;
if (size != 8)
memcpy (ecif.rvalue, ecif.rvalue + 8-size, size);
}
}
}
break;
default:
FFI_ASSERT(0);
break;
}
}

View File

@@ -0,0 +1,48 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 2004 Renesas Technology.
Target configuration macros for M32R.
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 RENESAS TECHNOLOGY 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
/* ---- Generic type definitions ----------------------------------------- */
#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
#define FFI_CLOSURES 0
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0
#endif

121
libffi/src/m32r/sysv.S Normal file
View File

@@ -0,0 +1,121 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 2004 Renesas Technology
M32R 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 RENESAS TECHNOLOGY 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
/* XXX these lose for some platforms, I'm sure. */
#define CNAME(x) x
#define ENTRY(x) .globl CNAME(x)! .type CNAME(x),%function! CNAME(x):
#endif
.text
/* R0: ffi_prep_args */
/* R1: &ecif */
/* R2: cif->bytes */
/* R3: fig->flags */
/* sp+0: ecif.rvalue */
/* sp+4: fn */
/* This assumes we are using gas. */
ENTRY(ffi_call_SYSV)
/* Save registers. */
push fp
push lr
push r3
push r2
push r1
push r0
mv fp, sp
/* Make room for all of the new args. */
sub sp, r2
/* Place all of the ffi_prep_args in position. */
mv lr, r0
mv r0, sp
/* R1 already set. */
/* And call. */
jl lr
/* Move first 4 parameters in registers... */
ld r0, @(0,sp)
ld r1, @(4,sp)
ld r2, @(8,sp)
ld r3, @(12,sp)
/* ...and adjust the stack. */
ld lr, @(8,fp)
cmpi lr, #16
bc adjust_stack
ldi lr, #16
adjust_stack:
add sp, lr
/* Call the function. */
ld lr, @(28,fp)
jl lr
/* Remove the space we pushed for the args. */
mv sp, fp
/* Load R2 with the pointer to storage for the return value. */
ld r2, @(24,sp)
/* Load R3 with the return type code. */
ld r3, @(12,sp)
/* If the return value pointer is NULL, assume no return value. */
beqz r2, epilogue
/* Return INT. */
ldi r4, #FFI_TYPE_INT
bne r3, r4, return_double
st r0, @r2
bra epilogue
return_double:
/* Return DOUBLE or LONGDOUBLE. */
ldi r4, #FFI_TYPE_DOUBLE
bne r3, r4, epilogue
st r0, @r2
st r1, @(4,r2)
epilogue:
pop r0
pop r1
pop r2
pop r3
pop lr
pop fp
jmp lr
.ffi_call_SYSV_end:
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)

176
libffi/src/m68k/ffi.c Normal file
View File

@@ -0,0 +1,176 @@
/* -----------------------------------------------------------------------
ffi.c
m68k Foreign Function Interface
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space has
been allocated for the function's arguments. */
static void *
ffi_prep_args (void *stack, extended_cif *ecif)
{
unsigned int i;
void **p_argv;
char *argp;
ffi_type **p_arg;
void *struct_value_ptr;
argp = stack;
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
&& ecif->cif->rtype->size > 8)
struct_value_ptr = ecif->rvalue;
else
struct_value_ptr = NULL;
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
i != 0;
i--, p_arg++)
{
size_t z;
/* Align if necessary. */
if (((*p_arg)->alignment - 1) & (unsigned) argp)
argp = (char *) ALIGN (argp, (*p_arg)->alignment);
z = (*p_arg)->size;
if (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;
break;
case FFI_TYPE_STRUCT:
memcpy (argp + sizeof (int) - z, *p_argv, z);
break;
default:
FFI_ASSERT (0);
}
z = sizeof (int);
}
else
memcpy (argp, *p_argv, z);
p_argv++;
argp += z;
}
return struct_value_ptr;
}
#define CIF_FLAGS_INT 1
#define CIF_FLAGS_DINT 2
#define CIF_FLAGS_FLOAT 4
#define CIF_FLAGS_DOUBLE 8
#define CIF_FLAGS_LDOUBLE 16
#define CIF_FLAGS_POINTER 32
#define CIF_FLAGS_STRUCT 64
/* Perform machine dependent cif processing */
ffi_status
ffi_prep_cif_machdep (ffi_cif *cif)
{
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
cif->flags = 0;
break;
case FFI_TYPE_STRUCT:
if (cif->rtype->size > 4 && cif->rtype->size <= 8)
cif->flags = CIF_FLAGS_DINT;
else if (cif->rtype->size <= 4)
cif->flags = CIF_FLAGS_STRUCT;
else
cif->flags = 0;
break;
case FFI_TYPE_FLOAT:
cif->flags = CIF_FLAGS_FLOAT;
break;
case FFI_TYPE_DOUBLE:
cif->flags = CIF_FLAGS_DOUBLE;
break;
case FFI_TYPE_LONGDOUBLE:
cif->flags = CIF_FLAGS_LDOUBLE;
break;
case FFI_TYPE_POINTER:
cif->flags = CIF_FLAGS_POINTER;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags = CIF_FLAGS_DINT;
break;
default:
cif->flags = CIF_FLAGS_INT;
break;
}
return FFI_OK;
}
extern void ffi_call_SYSV (void *(*) (void *, extended_cif *),
extended_cif *,
unsigned, unsigned, unsigned,
void *, void (*fn) ());
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
&& cif->rtype->size > 8)
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, cif->rtype->size * 8,
ecif.rvalue, fn);
break;
default:
FFI_ASSERT (0);
break;
}
}

View File

@@ -0,0 +1,47 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for Motorola 68K.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#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 0
#define FFI_NATIVE_RAW_API 0
#endif

97
libffi/src/m68k/sysv.S Normal file
View File

@@ -0,0 +1,97 @@
/* -----------------------------------------------------------------------
sysv.S
m68k Foreign Function Interface
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.text
.globl ffi_call_SYSV
.type ffi_call_SYSV,@function
ffi_call_SYSV:
link %fp,#0
move.l %d2,-(%sp)
| Make room for all of the new args.
sub.l 16(%fp),%sp
| Call ffi_prep_args
move.l 12(%fp),-(%sp)
pea 4(%sp)
move.l 8(%fp),%a0
jsr (%a0)
addq.l #8,%sp
| Pass pointer to struct value, if any
move.l %a0,%a1
| Call the function
move.l 32(%fp),%a0
jsr (%a0)
| Remove the space we pushed for the args
add.l 16(%fp),%sp
| Load the pointer to storage for the return value
move.l 28(%fp),%a1
| Load the return type code
move.l 20(%fp),%d2
| If the return value pointer is NULL, assume no return value.
tst.l %a1
jbeq noretval
btst #0,%d2
jbeq retlongint
move.l %d0,(%a1)
jbra epilogue
retlongint:
btst #1,%d2
jbeq retfloat
move.l %d0,(%a1)
move.l %d1,4(%a1)
jbra epilogue
retfloat:
btst #2,%d2
jbeq retdouble
fmove.s %fp0,(%a1)
jbra epilogue
retdouble:
btst #3,%d2
jbeq retlongdouble
fmove.d %fp0,(%a1)
jbra epilogue
retlongdouble:
btst #4,%d2
jbeq retpointer
fmove.x %fp0,(%a1)
jbra epilogue
retpointer:
btst #5,%d2
jbeq retstruct
move.l %a0,(%a1)
jbra epilogue
retstruct:
btst #6,%d2
jbeq noretval
move.l 24(%fp),%d2
bfins %d0,(%a1){#0,%d2}
noretval:
epilogue:
move.l (%sp)+,%d2
unlk %a6
rts
.size ffi_call_SYSV,.-ffi_call_SYSV

648
libffi/src/mips/ffi.c Normal file
View File

@@ -0,0 +1,648 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996 Red Hat, Inc.
MIPS 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <sys/cachectl.h>
#if _MIPS_SIM == _ABIN32
#define FIX_ARGP \
FFI_ASSERT(argp <= &stack[bytes]); \
if (argp == &stack[bytes]) \
{ \
argp = stack; \
ffi_stop_here(); \
}
#else
#define FIX_ARGP
#endif
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
static void ffi_prep_args(char *stack,
extended_cif *ecif,
int bytes,
int flags)
{
int i;
void **p_argv;
char *argp;
ffi_type **p_arg;
#if _MIPS_SIM == _ABIN32
/* If more than 8 double words are used, the remainder go
on the stack. We reorder stuff on the stack here to
support this easily. */
if (bytes > 8 * sizeof(ffi_arg))
argp = &stack[bytes - (8 * sizeof(ffi_arg))];
else
argp = stack;
#else
argp = stack;
#endif
memset(stack, 0, bytes);
#if _MIPS_SIM == _ABIN32
if ( ecif->cif->rstruct_flag != 0 )
#else
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
#endif
{
*(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
argp += sizeof(ffi_arg);
FIX_ARGP;
}
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
{
size_t z;
unsigned int a;
/* Align if necessary. */
a = (*p_arg)->alignment;
if (a < sizeof(ffi_arg))
a = sizeof(ffi_arg);
if ((a - 1) & (unsigned int) argp)
{
argp = (char *) ALIGN(argp, a);
FIX_ARGP;
}
z = (*p_arg)->size;
if (z <= sizeof(ffi_arg))
{
z = sizeof(ffi_arg);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(ffi_arg *)argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(ffi_arg *)argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(ffi_arg *)argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(ffi_arg *)argp = *(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(ffi_arg *)argp = *(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER:
*(ffi_arg *)argp = *(UINT32 *)(* p_argv);
break;
/* This can only happen with 64bit slots. */
case FFI_TYPE_FLOAT:
*(float *) argp = *(float *)(* p_argv);
break;
/* Handle small structures. */
case FFI_TYPE_STRUCT:
default:
memcpy(argp, *p_argv, (*p_arg)->size);
break;
}
}
else
{
#if _MIPS_SIM == _ABIO32
memcpy(argp, *p_argv, z);
#else
{
unsigned end = (unsigned) argp+z;
unsigned cap = (unsigned) stack+bytes;
/* Check if the data will fit within the register space.
Handle it if it doesn't. */
if (end <= cap)
memcpy(argp, *p_argv, z);
else
{
unsigned portion = end - cap;
memcpy(argp, *p_argv, portion);
argp = stack;
memcpy(argp,
(void*)((unsigned)(*p_argv)+portion), z - portion);
}
}
#endif
}
p_argv++;
argp += z;
FIX_ARGP;
}
}
#if _MIPS_SIM == _ABIN32
/* The n32 spec says that if "a chunk consists solely of a double
float field (but not a double, which is part of a union), it
is passed in a floating point register. Any other chunk is
passed in an integer register". This code traverses structure
definitions and generates the appropriate flags. */
unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
{
unsigned flags = 0;
unsigned index = 0;
ffi_type *e;
while (e = arg->elements[index])
{
if (e->type == FFI_TYPE_DOUBLE)
{
flags += (FFI_TYPE_DOUBLE << *shift);
*shift += FFI_FLAG_BITS;
}
else if (e->type == FFI_TYPE_STRUCT)
flags += calc_n32_struct_flags(e, shift);
else
*shift += FFI_FLAG_BITS;
index++;
}
return flags;
}
unsigned calc_n32_return_struct_flags(ffi_type *arg)
{
unsigned flags = 0;
unsigned index = 0;
unsigned small = FFI_TYPE_SMALLSTRUCT;
ffi_type *e;
/* Returning structures under n32 is a tricky thing.
A struct with only one or two floating point fields
is returned in $f0 (and $f2 if necessary). Any other
struct results at most 128 bits are returned in $2
(the first 64 bits) and $3 (remainder, if necessary).
Larger structs are handled normally. */
if (arg->size > 16)
return 0;
if (arg->size > 8)
small = FFI_TYPE_SMALLSTRUCT2;
e = arg->elements[0];
if (e->type == FFI_TYPE_DOUBLE)
flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
else if (e->type == FFI_TYPE_FLOAT)
flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
if (flags && (e = arg->elements[1]))
{
if (e->type == FFI_TYPE_DOUBLE)
flags += FFI_TYPE_DOUBLE;
else if (e->type == FFI_TYPE_FLOAT)
flags += FFI_TYPE_FLOAT;
else
return small;
if (flags && (arg->elements[2]))
{
/* There are three arguments and the first two are
floats! This must be passed the old way. */
return small;
}
}
else
if (!flags)
return small;
return flags;
}
#endif
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
cif->flags = 0;
#if _MIPS_SIM == _ABIO32
/* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT
* does not have special handling for floating point args.
*/
if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32)
{
if (cif->nargs > 0)
{
switch ((cif->arg_types)[0]->type)
{
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
cif->flags += (cif->arg_types)[0]->type;
break;
default:
break;
}
if (cif->nargs > 1)
{
/* Only handle the second argument if the first
is a float or double. */
if (cif->flags)
{
switch ((cif->arg_types)[1]->type)
{
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS;
break;
default:
break;
}
}
}
}
}
/* Set the return type flag */
if (cif->abi == FFI_O32_SOFT_FLOAT)
{
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_DOUBLE:
cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
break;
case FFI_TYPE_FLOAT:
default:
cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
break;
}
}
else
{
/* FFI_O32 */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
break;
default:
cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
break;
}
}
#endif
#if _MIPS_SIM == _ABIN32
/* Set the flags necessary for N32 processing */
{
unsigned shift = 0;
unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
unsigned index = 0;
unsigned struct_flags = 0;
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
struct_flags = calc_n32_return_struct_flags(cif->rtype);
if (struct_flags == 0)
{
/* This means that the structure is being passed as
a hidden argument */
shift = FFI_FLAG_BITS;
count = (cif->nargs < 7) ? cif->nargs : 7;
cif->rstruct_flag = !0;
}
else
cif->rstruct_flag = 0;
}
else
cif->rstruct_flag = 0;
while (count-- > 0)
{
switch ((cif->arg_types)[index]->type)
{
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
cif->flags += ((cif->arg_types)[index]->type << shift);
shift += FFI_FLAG_BITS;
break;
case FFI_TYPE_STRUCT:
cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
&shift);
break;
default:
shift += FFI_FLAG_BITS;
}
index++;
}
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_STRUCT:
{
if (struct_flags == 0)
{
/* The structure is returned through a hidden
first argument. Do nothing, 'cause FFI_TYPE_VOID
is 0 */
}
else
{
/* The structure is returned via some tricky
mechanism */
cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
}
break;
}
case FFI_TYPE_VOID:
/* Do nothing, 'cause FFI_TYPE_VOID is 0 */
break;
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
break;
default:
cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
break;
}
}
#endif
return FFI_OK;
}
/* Low level routine for calling O32 functions */
extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
extended_cif *, unsigned,
unsigned, unsigned *, void (*)());
/* Low level routine for calling N32 functions */
extern int ffi_call_N32(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;
/* 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)
{
#if _MIPS_SIM == _ABIO32
case FFI_O32:
case FFI_O32_SOFT_FLOAT:
ffi_call_O32(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
#endif
#if _MIPS_SIM == _ABIN32
case FFI_N32:
ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
#endif
default:
FFI_ASSERT(0);
break;
}
}
#if FFI_CLOSURES /* N32 not implemented yet, FFI_CLOSURES not defined */
#if defined(FFI_MIPS_O32)
extern void ffi_closure_O32(void);
#endif /* FFI_MIPS_O32 */
ffi_status
ffi_prep_closure (ffi_closure *closure,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
unsigned int fn;
unsigned int ctx = (unsigned int) closure;
#if defined(FFI_MIPS_O32)
FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT);
fn = (unsigned int) ffi_closure_O32;
#else /* FFI_MIPS_N32 */
FFI_ASSERT(cif->abi == FFI_N32);
FFI_ASSERT(!"not implemented");
#endif /* FFI_MIPS_O32 */
tramp[0] = 0x3c190000 | (fn >> 16); /* lui $25,high(fn) */
tramp[1] = 0x37390000 | (fn & 0xffff); /* ori $25,low(fn) */
tramp[2] = 0x3c080000 | (ctx >> 16); /* lui $8,high(ctx) */
tramp[3] = 0x03200008; /* jr $25 */
tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori $8,low(ctx) */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* XXX this is available on Linux, but anything else? */
cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE);
return FFI_OK;
}
/*
* Decodes the arguments to a function, which will be stored on the
* stack. AR is the pointer to the beginning of the integer arguments
* (and, depending upon the arguments, some floating-point arguments
* as well). FPR is a pointer to the area where floating point
* registers have been saved, if any.
*
* RVALUE is the location where the function return value will be
* stored. CLOSURE is the prepared closure to invoke.
*
* This function should only be called from assembly, which is in
* turn called from a trampoline.
*
* Returns the function return type.
*
* Based on the similar routine for sparc.
*/
int
ffi_closure_mips_inner_O32 (ffi_closure *closure,
void *rvalue, ffi_arg *ar,
double *fpr)
{
ffi_cif *cif;
void **avaluep;
ffi_arg *avalue;
ffi_type **arg_types;
int i, avn, argn, seen_int;
cif = closure->cif;
avalue = alloca (cif->nargs * sizeof (ffi_arg));
avaluep = alloca (cif->nargs * sizeof (ffi_arg));
seen_int = (cif->abi == FFI_O32_SOFT_FLOAT);
argn = 0;
if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
{
rvalue = (void *) ar[0];
argn = 1;
}
i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
while (i < avn)
{
if (i < 2 && !seen_int &&
(arg_types[i]->type == FFI_TYPE_FLOAT ||
arg_types[i]->type == FFI_TYPE_DOUBLE))
{
#ifdef __MIPSEB__
if (arg_types[i]->type == FFI_TYPE_FLOAT)
avaluep[i] = ((char *) &fpr[i]) + sizeof (float);
else
#endif
avaluep[i] = (char *) &fpr[i];
}
else
{
if (arg_types[i]->alignment == 8 && (argn & 0x1))
argn++;
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
avaluep[i] = &avalue[i];
*(SINT8 *) &avalue[i] = (SINT8) ar[argn];
break;
case FFI_TYPE_UINT8:
avaluep[i] = &avalue[i];
*(UINT8 *) &avalue[i] = (UINT8) ar[argn];
break;
case FFI_TYPE_SINT16:
avaluep[i] = &avalue[i];
*(SINT16 *) &avalue[i] = (SINT16) ar[argn];
break;
case FFI_TYPE_UINT16:
avaluep[i] = &avalue[i];
*(UINT16 *) &avalue[i] = (UINT16) ar[argn];
break;
default:
avaluep[i] = (char *) &ar[argn];
break;
}
seen_int = 1;
}
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
i++;
}
/* Invoke the closure. */
(closure->fun) (cif, rvalue, avaluep, closure->user_data);
if (cif->abi == FFI_O32_SOFT_FLOAT)
{
switch (cif->rtype->type)
{
case FFI_TYPE_FLOAT:
return FFI_TYPE_INT;
case FFI_TYPE_DOUBLE:
return FFI_TYPE_UINT64;
default:
return cif->rtype->type;
}
}
else
{
return cif->rtype->type;
}
}
#endif /* FFI_CLOSURES */

167
libffi/src/mips/ffitarget.h Normal file
View File

@@ -0,0 +1,167 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for MIPS.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#if !defined(_MIPS_SIM)
-- something is very wrong --
#else
# if (_MIPS_SIM==_ABIN32 && defined(_ABIN32)) || (_MIPS_SIM==_ABI64 && defined(_ABI64))
# define FFI_MIPS_N32
# else
# if (_MIPS_SIM==_ABIO32 && defined(_ABIO32))
# define FFI_MIPS_O32
# else
-- this is an unsupported platform --
# endif
# endif
#endif
#ifdef FFI_MIPS_O32
/* O32 stack frames have 32bit integer args */
#define FFI_SIZEOF_ARG 4
#else
/* N32 and N64 frames have 64bit integer args */
#define FFI_SIZEOF_ARG 8
#endif
#define FFI_FLAG_BITS 2
/* SGI's strange assembler requires that we multiply by 4 rather
than shift left by FFI_FLAG_BITS */
#define FFI_ARGS_D FFI_TYPE_DOUBLE
#define FFI_ARGS_F FFI_TYPE_FLOAT
#define FFI_ARGS_DD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_DOUBLE
#define FFI_ARGS_FF FFI_TYPE_FLOAT * 4 + FFI_TYPE_FLOAT
#define FFI_ARGS_FD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_FLOAT
#define FFI_ARGS_DF FFI_TYPE_FLOAT * 4 + FFI_TYPE_DOUBLE
/* Needed for N32 structure returns */
#define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8
#define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8
#if 0
/* The SGI assembler can't handle this.. */
#define FFI_TYPE_STRUCT_DD (( FFI_ARGS_DD ) << 4) + FFI_TYPE_STRUCT
/* (and so on) */
#else
/* ...so we calculate these by hand! */
#define FFI_TYPE_STRUCT_D 61
#define FFI_TYPE_STRUCT_F 45
#define FFI_TYPE_STRUCT_DD 253
#define FFI_TYPE_STRUCT_FF 173
#define FFI_TYPE_STRUCT_FD 237
#define FFI_TYPE_STRUCT_DF 189
#define FFI_TYPE_STRUCT_SMALL 93
#define FFI_TYPE_STRUCT_SMALL2 109
#endif
#ifdef LIBFFI_ASM
#define v0 $2
#define v1 $3
#define a0 $4
#define a1 $5
#define a2 $6
#define a3 $7
#define a4 $8
#define a5 $9
#define a6 $10
#define a7 $11
#define t0 $8
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define t8 $24
#define t9 $25
#define ra $31
#ifdef FFI_MIPS_O32
#define REG_L lw
#define REG_S sw
#define SUBU subu
#define ADDU addu
#define SRL srl
#define LI li
#else /* !FFI_MIPS_O32 */
#define REG_L ld
#define REG_S sd
#define SUBU dsubu
#define ADDU daddu
#define SRL dsrl
#define LI dli
#endif /* !FFI_MIPS_O32 */
#else /* !LIBFFI_ASM */
#ifdef FFI_MIPS_O32
/* O32 stack frames have 32bit integer args */
typedef unsigned int ffi_arg __attribute__((__mode__(__SI__)));
typedef signed int ffi_sarg __attribute__((__mode__(__SI__)));
#else
/* N32 and N64 frames have 64bit integer args */
typedef unsigned int ffi_arg __attribute__((__mode__(__DI__)));
typedef signed int ffi_sarg __attribute__((__mode__(__DI__)));
#endif
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
FFI_O32,
FFI_N32,
FFI_N64,
FFI_O32_SOFT_FLOAT,
#ifdef FFI_MIPS_O32
#ifdef __mips_soft_float
FFI_DEFAULT_ABI = FFI_O32_SOFT_FLOAT,
#else
FFI_DEFAULT_ABI = FFI_O32,
#endif
#else
FFI_DEFAULT_ABI = FFI_N32,
#endif
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
} ffi_abi;
#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag
#endif /* !LIBFFI_ASM */
/* ---- Definitions for closures ----------------------------------------- */
#if defined(FFI_MIPS_O32)
#define FFI_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 20
#else
/* N32/N64 not implemented yet. */
#define FFI_CLOSURES 0
#endif /* FFI_MIPS_O32 */
#define FFI_NATIVE_RAW_API 0
#endif

320
libffi/src/mips/n32.S Normal file
View File

@@ -0,0 +1,320 @@
/* -----------------------------------------------------------------------
n32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
MIPS 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 <fficonfig.h>
#include <ffi.h>
/* Only build this code if we are compiling for n32 */
#if defined(FFI_MIPS_N32)
#define callback a0
#define bytes a2
#define flags a3
#define raddr a4
#define fn a5
#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
.abicalls
.text
.align 2
.globl ffi_call_N32
.ent ffi_call_N32
ffi_call_N32:
# Prologue
SUBU $sp, SIZEOF_FRAME # Frame size
REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
move $fp, $sp
move t9, callback # callback function pointer
REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
# Allocate at least 4 words in the argstack
move v0, bytes
bge bytes, 4 * FFI_SIZEOF_ARG, bigger
LI v0, 4 * FFI_SIZEOF_ARG
b sixteen
bigger:
ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry.
sixteen:
SUBU $sp, $sp, v0 # move the stack pointer to reflect the
# arg space
ADDU a0, $sp, 0 # 4 * FFI_SIZEOF_ARG
ADDU a3, $fp, 3 * FFI_SIZEOF_ARG
# Call ffi_prep_args
jal t9
# ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
# Copy the stack pointer to t9
move t9, $sp
# Fix the stack if there are more than 8 64bit slots worth
# of arguments.
# Load the number of bytes
REG_L t6, 2*FFI_SIZEOF_ARG($fp)
# Is it bigger than 8 * FFI_SIZEOF_ARG?
dadd t7, $0, 8 * FFI_SIZEOF_ARG
dsub t8, t6, t7
bltz t8, loadregs
add t9, t9, t8
loadregs:
REG_L t4, 3*FFI_SIZEOF_ARG($fp) # load the flags word
add t6, t4, 0 # and copy it into t6
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg1_floatp
REG_L a0, 0*FFI_SIZEOF_ARG(t9)
b arg1_next
arg1_floatp:
bne t4, FFI_TYPE_FLOAT, arg1_doublep
l.s $f12, 0*FFI_SIZEOF_ARG(t9)
b arg1_next
arg1_doublep:
l.d $f12, 0*FFI_SIZEOF_ARG(t9)
arg1_next:
add t4, t6, 0
SRL t4, 1*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg2_floatp
REG_L a1, 1*FFI_SIZEOF_ARG(t9)
b arg2_next
arg2_floatp:
bne t4, FFI_TYPE_FLOAT, arg2_doublep
l.s $f13, 1*FFI_SIZEOF_ARG(t9)
b arg2_next
arg2_doublep:
l.d $f13, 1*FFI_SIZEOF_ARG(t9)
arg2_next:
add t4, t6, 0
SRL t4, 2*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg3_floatp
REG_L a2, 2*FFI_SIZEOF_ARG(t9)
b arg3_next
arg3_floatp:
bne t4, FFI_TYPE_FLOAT, arg3_doublep
l.s $f14, 2*FFI_SIZEOF_ARG(t9)
b arg3_next
arg3_doublep:
l.d $f14, 2*FFI_SIZEOF_ARG(t9)
arg3_next:
add t4, t6, 0
SRL t4, 3*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg4_floatp
REG_L a3, 3*FFI_SIZEOF_ARG(t9)
b arg4_next
arg4_floatp:
bne t4, FFI_TYPE_FLOAT, arg4_doublep
l.s $f15, 3*FFI_SIZEOF_ARG(t9)
b arg4_next
arg4_doublep:
l.d $f15, 3*FFI_SIZEOF_ARG(t9)
arg4_next:
add t4, t6, 0
SRL t4, 4*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg5_floatp
REG_L a4, 4*FFI_SIZEOF_ARG(t9)
b arg5_next
arg5_floatp:
bne t4, FFI_TYPE_FLOAT, arg5_doublep
l.s $f16, 4*FFI_SIZEOF_ARG(t9)
b arg5_next
arg5_doublep:
l.d $f16, 4*FFI_SIZEOF_ARG(t9)
arg5_next:
add t4, t6, 0
SRL t4, 5*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg6_floatp
REG_L a5, 5*FFI_SIZEOF_ARG(t9)
b arg6_next
arg6_floatp:
bne t4, FFI_TYPE_FLOAT, arg6_doublep
l.s $f17, 5*FFI_SIZEOF_ARG(t9)
b arg6_next
arg6_doublep:
l.d $f17, 5*FFI_SIZEOF_ARG(t9)
arg6_next:
add t4, t6, 0
SRL t4, 6*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg7_floatp
REG_L a6, 6*FFI_SIZEOF_ARG(t9)
b arg7_next
arg7_floatp:
bne t4, FFI_TYPE_FLOAT, arg7_doublep
l.s $f18, 6*FFI_SIZEOF_ARG(t9)
b arg7_next
arg7_doublep:
l.d $f18, 6*FFI_SIZEOF_ARG(t9)
arg7_next:
add t4, t6, 0
SRL t4, 7*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg8_floatp
REG_L a7, 7*FFI_SIZEOF_ARG(t9)
b arg8_next
arg8_floatp:
bne t4, FFI_TYPE_FLOAT, arg8_doublep
l.s $f19, 7*FFI_SIZEOF_ARG(t9)
b arg8_next
arg8_doublep:
l.d $f19, 7*FFI_SIZEOF_ARG(t9)
arg8_next:
callit:
# Load the function pointer
REG_L t9, 5*FFI_SIZEOF_ARG($fp)
# If the return value pointer is NULL, assume no return value.
REG_L t5, 4*FFI_SIZEOF_ARG($fp)
beqz t5, noretval
# Shift the return type flag over
SRL t6, 8*FFI_FLAG_BITS
bne t6, FFI_TYPE_INT, retfloat
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
REG_S v0, 0(t4)
b epilogue
retfloat:
bne t6, FFI_TYPE_FLOAT, retdouble
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.s $f0, 0(t4)
b epilogue
retdouble:
bne t6, FFI_TYPE_DOUBLE, retstruct_d
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.d $f0, 0(t4)
b epilogue
retstruct_d:
bne t6, FFI_TYPE_STRUCT_D, retstruct_f
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.d $f0, 0(t4)
b epilogue
retstruct_f:
bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.s $f0, 0(t4)
b epilogue
retstruct_d_d:
bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.d $f0, 0(t4)
s.d $f2, 8(t4)
b epilogue
retstruct_f_f:
bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.s $f0, 0(t4)
s.s $f2, 4(t4)
b epilogue
retstruct_d_f:
bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.d $f0, 0(t4)
s.s $f2, 8(t4)
b epilogue
retstruct_f_d:
bne t6, FFI_TYPE_STRUCT_FD, retstruct_small
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
s.s $f0, 0(t4)
s.d $f2, 8(t4)
b epilogue
retstruct_small:
bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
REG_S v0, 0(t4)
b epilogue
retstruct_small2:
bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
REG_S v0, 0(t4)
REG_S v1, 8(t4)
b epilogue
retstruct:
noretval:
jal t9
# Epilogue
epilogue:
move $sp, $fp
REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
ADDU $sp, SIZEOF_FRAME # Fix stack pointer
j ra
.end ffi_call_N32
#endif

377
libffi/src/mips/o32.S Normal file
View File

@@ -0,0 +1,377 @@
/* -----------------------------------------------------------------------
o32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
MIPS 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 <fficonfig.h>
#include <ffi.h>
/* Only build this code if we are compiling for o32 */
#if defined(FFI_MIPS_O32)
#define callback a0
#define bytes a2
#define flags a3
#define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG)
#define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG)
#define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG)
#define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG)
.abicalls
.text
.align 2
.globl ffi_call_O32
.ent ffi_call_O32
ffi_call_O32:
$LFB0:
# Prologue
SUBU $sp, SIZEOF_FRAME # Frame size
$LCFI0:
REG_S $fp, FP_OFF($sp) # Save frame pointer
$LCFI1:
REG_S ra, RA_OFF($sp) # Save return address
$LCFI2:
move $fp, $sp
$LCFI3:
move t9, callback # callback function pointer
REG_S flags, A3_OFF($fp) # flags
# Allocate at least 4 words in the argstack
LI v0, 4 * FFI_SIZEOF_ARG
blt bytes, v0, sixteen
ADDU v0, bytes, 7 # make sure it is aligned
and v0, -8 # to an 8 byte boundry
sixteen:
SUBU $sp, v0 # move the stack pointer to reflect the
# arg space
ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
jalr t9
REG_L t0, A3_OFF($fp) # load the flags word
SRL t2, t0, 4 # shift our arg info
and t0, ((1<<4)-1) # mask out the return type
ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
bnez t0, pass_d # make it quick for int
REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
REG_L a2, 2*FFI_SIZEOF_ARG($sp)
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
b call_it
pass_d:
bne t0, FFI_ARGS_D, pass_f
l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
b call_it
pass_f:
bne t0, FFI_ARGS_F, pass_d_d
l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float
REG_L a2, 2*FFI_SIZEOF_ARG($sp)
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
b call_it
pass_d_d:
bne t0, FFI_ARGS_DD, pass_f_f
l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles
b call_it
pass_f_f:
bne t0, FFI_ARGS_FF, pass_d_f
l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats
REG_L a2, 2*FFI_SIZEOF_ARG($sp)
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
b call_it
pass_d_f:
bne t0, FFI_ARGS_DF, pass_f_d
l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
b call_it
pass_f_d:
# assume that the only other combination must be float then double
# bne t0, FFI_ARGS_F_D, call_it
l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
call_it:
# Load the function pointer
REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
# If the return value pointer is NULL, assume no return value.
REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
beqz t1, noretval
bne t2, FFI_TYPE_INT, retlonglong
jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
REG_S v0, 0(t0)
b epilogue
retlonglong:
# Really any 64-bit int, signed or not.
bne t2, FFI_TYPE_UINT64, retfloat
jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
REG_S v1, 4(t0)
REG_S v0, 0(t0)
b epilogue
retfloat:
bne t2, FFI_TYPE_FLOAT, retdouble
jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
s.s $f0, 0(t0)
b epilogue
retdouble:
bne t2, FFI_TYPE_DOUBLE, noretval
jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
s.d $f0, 0(t0)
b epilogue
noretval:
jalr t9
# Epilogue
epilogue:
move $sp, $fp
REG_L $fp, FP_OFF($sp) # Restore frame pointer
REG_L ra, RA_OFF($sp) # Restore return address
ADDU $sp, SIZEOF_FRAME # Fix stack pointer
j ra
$LFE0:
.end ffi_call_O32
/* ffi_closure_O32. Expects address of the passed-in ffi_closure
in t0. Stores any arguments passed in registers onto the
stack, then calls ffi_closure_mips_inner_O32, which
then decodes them.
Stack layout:
14 - Start of parameters, original sp
13 - ra save
12 - fp save
11 - $16 (s0) save
10 - cprestore
9 - return value high (v1)
8 - return value low (v0)
7 - f14 (le high, be low)
6 - f14 (le low, be high)
5 - f12 (le high, be low)
4 - f12 (le low, be high)
3 - Called function a3 save
2 - Called function a2 save
1 - Called function a1 save
0 - Called function a0 save our sp, fp point here
*/
#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
#define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
#define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
#define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
#define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
#define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
#define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
#define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
#define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
.text
.align 2
.globl ffi_closure_O32
.ent ffi_closure_O32
ffi_closure_O32:
$LFB1:
# Prologue
.frame $fp, SIZEOF_FRAME2, ra
.set noreorder
.cpload t9
.set reorder
SUBU $sp, SIZEOF_FRAME2
.cprestore GP_OFF2
$LCFI4:
REG_S $16, S0_OFF2($sp) # Save s0
REG_S $fp, FP_OFF2($sp) # Save frame pointer
REG_S ra, RA_OFF2($sp) # Save return address
$LCFI6:
move $fp, $sp
$LCFI7:
# Store all possible argument registers. If there are more than
# four arguments, then they are stored above where we put a3.
REG_S a0, A0_OFF2($fp)
REG_S a1, A1_OFF2($fp)
REG_S a2, A2_OFF2($fp)
REG_S a3, A3_OFF2($fp)
# Load ABI enum to s0
REG_L $16, 20($8) # cif pointer follows tramp.
REG_L $16, 0($16) # abi is first member.
li $13, 1 # FFI_O32
bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
# Store all possible float/double registers.
s.d $f12, FA_0_0_OFF2($fp)
s.d $f14, FA_1_0_OFF2($fp)
1:
# Call ffi_closure_mips_inner_O32 to do the work.
la t9, ffi_closure_mips_inner_O32
move a0, $8 # Pointer to the ffi_closure
addu a1, $fp, V0_OFF2
addu a2, $fp, A0_OFF2
addu a3, $fp, FA_0_0_OFF2
jalr t9
# Load the return value into the appropriate register.
move $8, $2
li $9, FFI_TYPE_VOID
beq $8, $9, closure_done
li $13, 1 # FFI_O32
bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
li $9, FFI_TYPE_FLOAT
l.s $f0, V0_OFF2($fp)
beq $8, $9, closure_done
li $9, FFI_TYPE_DOUBLE
l.d $f0, V0_OFF2($fp)
beq $8, $9, closure_done
1:
REG_L $3, V1_OFF2($fp)
REG_L $2, V0_OFF2($fp)
closure_done:
# Epilogue
move $sp, $fp
REG_L $16, S0_OFF2($sp) # Restore s0
REG_L $fp, FP_OFF2($sp) # Restore frame pointer
REG_L ra, RA_OFF2($sp) # Restore return address
ADDU $sp, SIZEOF_FRAME2
j ra
$LFE1:
.end ffi_closure_O32
/* DWARF-2 unwind info. */
.section .eh_frame,"a",@progbits
$Lframe0:
.4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
$LSCIE0:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.uleb128 0x1 # CIE Code Alignment Factor
.sleb128 4 # CIE Data Alignment Factor
.byte 0x1f # CIE RA Column
.uleb128 0x1 # Augmentation size
.byte 0x00 # FDE Encoding (absptr)
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1d
.uleb128 0x0
.align 2
$LECIE0:
$LSFDE0:
.4byte $LEFDE0-$LASFDE0 # FDE Length
$LASFDE0:
.4byte $LASFDE0-$Lframe0 # FDE CIE offset
.4byte $LFB0 # FDE initial location
.4byte $LFE0-$LFB0 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI0-$LFB0
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0x18
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI2-$LCFI0
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x1e # $fp
.sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x1f # $ra
.sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI3-$LCFI2
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1e
.uleb128 0x18
.align 2
$LEFDE0:
$LSFDE1:
.4byte $LEFDE1-$LASFDE1 # FDE Length
$LASFDE1:
.4byte $LASFDE1-$Lframe0 # FDE CIE offset
.4byte $LFB1 # FDE initial location
.4byte $LFE1-$LFB1 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI4-$LFB1
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0x38
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI6-$LCFI4
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x10 # $16
.sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x1e # $fp
.sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x1f # $ra
.sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI7-$LCFI6
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1e
.uleb128 0x38
.align 2
$LEFDE1:
#endif

706
libffi/src/pa/ffi.c Normal file
View File

@@ -0,0 +1,706 @@
/* -----------------------------------------------------------------------
ffi.c - (c) 2003-2004 Randolph Chung <tausq@debian.org>
HPPA Foreign Function Interface
HP-UX PA ABI support (c) 2006 Free Software Foundation, Inc.
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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <stdio.h>
#define ROUND_UP(v, a) (((size_t)(v) + (a) - 1) & ~((a) - 1))
#define MIN_STACK_SIZE 64
#define FIRST_ARG_SLOT 9
#define DEBUG_LEVEL 0
#define fldw(addr, fpreg) \
__asm__ volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
#define fstw(fpreg, addr) \
__asm__ volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr))
#define fldd(addr, fpreg) \
__asm__ volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg)
#define fstd(fpreg, addr) \
__asm__ volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
static inline int ffi_struct_type(ffi_type *t)
{
size_t sz = t->size;
/* Small structure results are passed in registers,
larger ones are passed by pointer. Note that
small structures of size 2, 4 and 8 differ from
the corresponding integer types in that they have
different alignment requirements. */
if (sz <= 1)
return FFI_TYPE_UINT8;
else if (sz == 2)
return FFI_TYPE_SMALL_STRUCT2;
else if (sz == 3)
return FFI_TYPE_SMALL_STRUCT3;
else if (sz == 4)
return FFI_TYPE_SMALL_STRUCT4;
else if (sz == 5)
return FFI_TYPE_SMALL_STRUCT5;
else if (sz == 6)
return FFI_TYPE_SMALL_STRUCT6;
else if (sz == 7)
return FFI_TYPE_SMALL_STRUCT7;
else if (sz <= 8)
return FFI_TYPE_SMALL_STRUCT8;
else
return FFI_TYPE_STRUCT; /* else, we pass it by pointer. */
}
/* PA has a downward growing stack, which looks like this:
Offset
[ Variable args ]
SP = (4*(n+9)) arg word N
...
SP-52 arg word 4
[ Fixed args ]
SP-48 arg word 3
SP-44 arg word 2
SP-40 arg word 1
SP-36 arg word 0
[ Frame marker ]
...
SP-20 RP
SP-4 previous SP
The first four argument words on the stack are reserved for use by
the callee. Instead, the general and floating registers replace
the first four argument slots. Non FP arguments are passed solely
in the general registers. FP arguments are passed in both general
and floating registers when using libffi.
Non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23.
Non-FP 64-bit args are passed in register pairs, starting
on an odd numbered register (i.e. r25+r26 and r23+r24).
FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L.
FP 64-bit arguments are passed in fr5 and fr7.
The registers are allocated in the same manner as stack slots.
This allows the callee to save its arguments on the stack if
necessary:
arg word 3 -> gr23 or fr7L
arg word 2 -> gr24 or fr6L or fr7R
arg word 1 -> gr25 or fr5L
arg word 0 -> gr26 or fr4L or fr5R
Note that fr4R and fr6R are never used for arguments (i.e.,
doubles are not passed in fr4 or fr6).
The rest of the arguments are passed on the stack starting at SP-52,
but 64-bit arguments need to be aligned to an 8-byte boundary
This means we can have holes either in the register allocation,
or in the stack. */
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments
The following code will put everything into the stack frame
(which was allocated by the asm routine), and on return
the asm routine will load the arguments that should be
passed by register into the appropriate registers
NOTE: We load floating point args in this function... that means we
assume gcc will not mess with fp regs in here. */
void ffi_prep_args_pa32(UINT32 *stack, extended_cif *ecif, unsigned bytes)
{
register unsigned int i;
register ffi_type **p_arg;
register void **p_argv;
unsigned int slot = FIRST_ARG_SLOT;
char *dest_cpy;
size_t len;
debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack,
ecif, bytes);
p_arg = ecif->cif->arg_types;
p_argv = ecif->avalue;
for (i = 0; i < ecif->cif->nargs; i++)
{
int type = (*p_arg)->type;
switch (type)
{
case FFI_TYPE_SINT8:
*(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv);
break;
case FFI_TYPE_UINT8:
*(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv);
break;
case FFI_TYPE_SINT16:
*(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv);
break;
case FFI_TYPE_UINT16:
*(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv);
break;
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv),
slot);
*(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
/* Align slot for 64-bit type. */
slot += (slot & 1) ? 1 : 2;
*(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
break;
case FFI_TYPE_FLOAT:
/* First 4 args go in fr4L - fr7L. */
debug(3, "Storing UINT32(float) in slot %u\n", slot);
*(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
switch (slot - FIRST_ARG_SLOT)
{
/* First 4 args go in fr4L - fr7L. */
case 0: fldw(stack - slot, fr4); break;
case 1: fldw(stack - slot, fr5); break;
case 2: fldw(stack - slot, fr6); break;
case 3: fldw(stack - slot, fr7); break;
}
break;
case FFI_TYPE_DOUBLE:
/* Align slot for 64-bit type. */
slot += (slot & 1) ? 1 : 2;
debug(3, "Storing UINT64(double) at slot %u\n", slot);
*(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
switch (slot - FIRST_ARG_SLOT)
{
/* First 2 args go in fr5, fr7. */
case 1: fldd(stack - slot, fr5); break;
case 3: fldd(stack - slot, fr7); break;
}
break;
#ifdef PA_HPUX
case FFI_TYPE_LONGDOUBLE:
/* Long doubles are passed in the same manner as structures
larger than 8 bytes. */
*(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
break;
#endif
case FFI_TYPE_STRUCT:
/* Structs smaller or equal than 4 bytes are passed in one
register. Structs smaller or equal 8 bytes are passed in two
registers. Larger structures are passed by pointer. */
len = (*p_arg)->size;
if (len <= 4)
{
dest_cpy = (char *)(stack - slot) + 4 - len;
memcpy(dest_cpy, (char *)*p_argv, len);
}
else if (len <= 8)
{
slot += (slot & 1) ? 1 : 2;
dest_cpy = (char *)(stack - slot) + 8 - len;
memcpy(dest_cpy, (char *)*p_argv, len);
}
else
*(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
break;
default:
FFI_ASSERT(0);
}
slot++;
p_arg++;
p_argv++;
}
/* Make sure we didn't mess up and scribble on the stack. */
{
unsigned int n;
debug(5, "Stack setup:\n");
for (n = 0; n < (bytes + 3) / 4; n++)
{
if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); }
debug(5, "%08x ", *(stack - n));
}
debug(5, "\n");
}
FFI_ASSERT(slot * 4 <= bytes);
return;
}
static void ffi_size_stack_pa32(ffi_cif *cif)
{
ffi_type **ptr;
int i;
int z = 0; /* # stack slots */
for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++)
{
int type = (*ptr)->type;
switch (type)
{
case FFI_TYPE_DOUBLE:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
z += 2 + (z & 1); /* must start on even regs, so we may waste one */
break;
#ifdef PA_HPUX
case FFI_TYPE_LONGDOUBLE:
#endif
case FFI_TYPE_STRUCT:
z += 1; /* pass by ptr, callee will copy */
break;
default: /* <= 32-bit values */
z++;
}
}
/* We can fit up to 6 args in the default 64-byte stack frame,
if we need more, we need more stack. */
if (z <= 6)
cif->bytes = MIN_STACK_SIZE; /* min stack size */
else
cif->bytes = 64 + ROUND_UP((z - 6) * sizeof(UINT32), MIN_STACK_SIZE);
debug(3, "Calculated stack size is %u bytes\n", cif->bytes);
}
/* Perform machine dependent cif processing. */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* 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;
#ifdef PA_HPUX
case FFI_TYPE_LONGDOUBLE:
/* Long doubles are treated like a structure. */
cif->flags = FFI_TYPE_STRUCT;
break;
#endif
case FFI_TYPE_STRUCT:
/* For the return type we have to check the size of the structures.
If the size is smaller or equal 4 bytes, the result is given back
in one register. If the size is smaller or equal 8 bytes than we
return the result in two registers. But if the size is bigger than
8 bytes, we work with pointers. */
cif->flags = ffi_struct_type(cif->rtype);
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
cif->flags = FFI_TYPE_UINT64;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
/* Lucky us, because of the unique PA ABI we get to do our
own stack sizing. */
switch (cif->abi)
{
case FFI_PA32:
ffi_size_stack_pa32(cif);
break;
default:
FFI_ASSERT(0);
break;
}
return FFI_OK;
}
extern void ffi_call_pa32(void (*)(UINT32 *, extended_cif *, unsigned),
extended_cif *, unsigned, unsigned, unsigned *,
void (*fn)());
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
#ifdef PA_HPUX
&& (cif->rtype->type == FFI_TYPE_STRUCT
|| cif->rtype->type == FFI_TYPE_LONGDOUBLE))
#else
&& cif->rtype->type == FFI_TYPE_STRUCT)
#endif
{
ecif.rvalue = alloca(cif->rtype->size);
}
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
case FFI_PA32:
debug(3, "Calling ffi_call_pa32: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
ffi_call_pa32(ffi_prep_args_pa32, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
default:
FFI_ASSERT(0);
break;
}
}
#if FFI_CLOSURES
/* This is more-or-less an inverse of ffi_call -- we have arguments on
the stack, and we need to fill them into a cif structure and invoke
the user function. This really ought to be in asm to make sure
the compiler doesn't do things we don't expect. */
ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
{
ffi_cif *cif;
void **avalue;
void *rvalue;
UINT32 ret[2]; /* function can return up to 64-bits in registers */
ffi_type **p_arg;
char *tmp;
int i, avn;
unsigned int slot = FIRST_ARG_SLOT;
register UINT32 r28 asm("r28");
cif = closure->cif;
/* If returning via structure, callee will write to our pointer. */
if (cif->flags == FFI_TYPE_STRUCT)
rvalue = (void *)r28;
else
rvalue = &ret[0];
avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG);
avn = cif->nargs;
p_arg = cif->arg_types;
for (i = 0; i < avn; i++)
{
int type = (*p_arg)->type;
switch (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_POINTER:
avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
slot += (slot & 1) ? 1 : 2;
avalue[i] = (void *)(stack - slot);
break;
case FFI_TYPE_FLOAT:
#ifdef PA_LINUX
/* The closure call is indirect. In Linux, floating point
arguments in indirect calls with a prototype are passed
in the floating point registers instead of the general
registers. So, we need to replace what was previously
stored in the current slot with the value in the
corresponding floating point register. */
switch (slot - FIRST_ARG_SLOT)
{
case 0: fstw(fr4, (void *)(stack - slot)); break;
case 1: fstw(fr5, (void *)(stack - slot)); break;
case 2: fstw(fr6, (void *)(stack - slot)); break;
case 3: fstw(fr7, (void *)(stack - slot)); break;
}
#endif
avalue[i] = (void *)(stack - slot);
break;
case FFI_TYPE_DOUBLE:
slot += (slot & 1) ? 1 : 2;
#ifdef PA_LINUX
/* See previous comment for FFI_TYPE_FLOAT. */
switch (slot - FIRST_ARG_SLOT)
{
case 1: fstd(fr5, (void *)(stack - slot)); break;
case 3: fstd(fr7, (void *)(stack - slot)); break;
}
#endif
avalue[i] = (void *)(stack - slot);
break;
case FFI_TYPE_STRUCT:
/* Structs smaller or equal than 4 bytes are passed in one
register. Structs smaller or equal 8 bytes are passed in two
registers. Larger structures are passed by pointer. */
if((*p_arg)->size <= 4)
{
avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
(*p_arg)->size;
}
else if ((*p_arg)->size <= 8)
{
slot += (slot & 1) ? 1 : 2;
avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
(*p_arg)->size;
}
else
avalue[i] = (void *) *(stack - slot);
break;
default:
FFI_ASSERT(0);
}
slot++;
p_arg++;
}
/* Invoke the closure. */
(closure->fun) (cif, rvalue, avalue, closure->user_data);
debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0],
ret[1]);
/* Store the result using the lower 2 bytes of the flags. */
switch (cif->flags)
{
case FFI_TYPE_UINT8:
*(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
break;
case FFI_TYPE_SINT8:
*(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
break;
case FFI_TYPE_UINT16:
*(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
break;
case FFI_TYPE_SINT16:
*(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
break;
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
*(stack - FIRST_ARG_SLOT) = ret[0];
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
*(stack - FIRST_ARG_SLOT) = ret[0];
*(stack - FIRST_ARG_SLOT - 1) = ret[1];
break;
case FFI_TYPE_DOUBLE:
fldd(rvalue, fr4);
break;
case FFI_TYPE_FLOAT:
fldw(rvalue, fr4);
break;
case FFI_TYPE_STRUCT:
/* Don't need a return value, done by caller. */
break;
case FFI_TYPE_SMALL_STRUCT2:
case FFI_TYPE_SMALL_STRUCT3:
case FFI_TYPE_SMALL_STRUCT4:
tmp = (void*)(stack - FIRST_ARG_SLOT);
tmp += 4 - cif->rtype->size;
memcpy((void*)tmp, &ret[0], cif->rtype->size);
break;
case FFI_TYPE_SMALL_STRUCT5:
case FFI_TYPE_SMALL_STRUCT6:
case FFI_TYPE_SMALL_STRUCT7:
case FFI_TYPE_SMALL_STRUCT8:
{
unsigned int ret2[2];
int off;
/* Right justify ret[0] and ret[1] */
switch (cif->flags)
{
case FFI_TYPE_SMALL_STRUCT5: off = 3; break;
case FFI_TYPE_SMALL_STRUCT6: off = 2; break;
case FFI_TYPE_SMALL_STRUCT7: off = 1; break;
default: off = 0; break;
}
memset (ret2, 0, sizeof (ret2));
memcpy ((char *)ret2 + off, ret, 8 - off);
*(stack - FIRST_ARG_SLOT) = ret2[0];
*(stack - FIRST_ARG_SLOT - 1) = ret2[1];
}
break;
case FFI_TYPE_POINTER:
case FFI_TYPE_VOID:
break;
default:
debug(0, "assert with cif->flags: %d\n",cif->flags);
FFI_ASSERT(0);
break;
}
return FFI_OK;
}
/* Fill in a closure to refer to the specified fun and user_data.
cif specifies the argument and result types for fun.
The cif must already be prep'ed. */
extern void ffi_closure_pa32(void);
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
UINT32 *tramp = (UINT32 *)(closure->tramp);
#ifdef PA_HPUX
UINT32 *tmp;
#endif
FFI_ASSERT (cif->abi == FFI_PA32);
/* Make a small trampoline that will branch to our
handler function. Use PC-relative addressing. */
#ifdef PA_LINUX
tramp[0] = 0xeaa00000; /* b,l .+8,%r21 ; %r21 <- pc+8 */
tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21 ; mask priv bits */
tramp[2] = 0x4aa10028; /* ldw 20(%r21),%r1 ; load plabel */
tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21 ; get closure addr */
tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22 ; address of handler */
tramp[5] = 0xeac0c000; /* bv%r0(%r22) ; branch to handler */
tramp[6] = 0x0c281093; /* ldw 4(%r1),%r19 ; GP of handler */
tramp[7] = ((UINT32)(ffi_closure_pa32) & ~2);
/* Flush d/icache -- have to flush up 2 two lines because of
alignment. */
__asm__ volatile(
"fdc 0(%0)\n\t"
"fdc %1(%0)\n\t"
"fic 0(%%sr4, %0)\n\t"
"fic %1(%%sr4, %0)\n\t"
"sync\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n"
:
: "r"((unsigned long)tramp & ~31),
"r"(32 /* stride */)
: "memory");
#endif
#ifdef PA_HPUX
tramp[0] = 0xeaa00000; /* b,l .+8,%r21 ; %r21 <- pc+8 */
tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21 ; mask priv bits */
tramp[2] = 0x4aa10038; /* ldw 28(%r21),%r1 ; load plabel */
tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21 ; get closure addr */
tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22 ; address of handler */
tramp[5] = 0x02c010b4; /* ldsid (%r22),%r20 ; load space id */
tramp[6] = 0x00141820; /* mtsp %r20,%sr0 ; into %sr0 */
tramp[7] = 0xe2c00000; /* be 0(%sr0,%r22) ; branch to handler */
tramp[8] = 0x0c281093; /* ldw 4(%r1),%r19 ; GP of handler */
tramp[9] = ((UINT32)(ffi_closure_pa32) & ~2);
/* Flush d/icache -- have to flush three lines because of alignment. */
__asm__ volatile(
"copy %1,%0\n\t"
"fdc,m %2(%0)\n\t"
"fdc,m %2(%0)\n\t"
"fdc,m %2(%0)\n\t"
"ldsid (%1),%0\n\t"
"mtsp %0,%%sr0\n\t"
"copy %1,%0\n\t"
"fic,m %2(%%sr0,%0)\n\t"
"fic,m %2(%%sr0,%0)\n\t"
"fic,m %2(%%sr0,%0)\n\t"
"sync\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n"
: "=&r" ((unsigned long)tmp)
: "r" ((unsigned long)tramp & ~31),
"r" (32/* stride */)
: "memory");
#endif
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
#endif

76
libffi/src/pa/ffitarget.h Normal file
View File

@@ -0,0 +1,76 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for hppa.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- System specific configurations ----------------------------------- */
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
#ifdef PA_LINUX
FFI_PA32,
FFI_DEFAULT_ABI = FFI_PA32,
#endif
#ifdef PA_HPUX
FFI_PA32,
FFI_DEFAULT_ABI = FFI_PA32,
#endif
#ifdef PA64_HPUX
#error "PA64_HPUX FFI is not yet implemented"
FFI_PA64,
FFI_DEFAULT_ABI = FFI_PA64,
#endif
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
#ifdef PA_LINUX
#define FFI_TRAMPOLINE_SIZE 32
#else
#define FFI_TRAMPOLINE_SIZE 40
#endif
#define FFI_TYPE_SMALL_STRUCT2 -1
#define FFI_TYPE_SMALL_STRUCT3 -2
#define FFI_TYPE_SMALL_STRUCT4 -3
#define FFI_TYPE_SMALL_STRUCT5 -4
#define FFI_TYPE_SMALL_STRUCT6 -5
#define FFI_TYPE_SMALL_STRUCT7 -6
#define FFI_TYPE_SMALL_STRUCT8 -7
#endif

367
libffi/src/pa/hpux32.S Normal file
View File

@@ -0,0 +1,367 @@
/* -----------------------------------------------------------------------
hpux32.S - Copyright (c) 2006 Free Software Foundation, Inc.
based on src/pa/linux.S
HP-UX PA 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.
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.LEVEL 1.1
.SPACE $PRIVATE$
.IMPORT $global$,DATA
.IMPORT $$dyncall,MILLICODE
.SUBSPA $DATA$
.align 4
/* void ffi_call_pa32(void (*)(char *, extended_cif *),
extended_cif *ecif,
unsigned bytes,
unsigned flags,
unsigned *rvalue,
void (*fn)());
*/
.export ffi_call_pa32,ENTRY,PRIV_LEV=3
.import ffi_prep_args_pa32,CODE
.SPACE $TEXT$
.SUBSPA $CODE$
.align 4
L$FB1
ffi_call_pa32
.proc
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
.entry
stw %rp, -20(%sp)
copy %r3, %r1
L$CFI11
copy %sp, %r3
L$CFI12
/* Setup the stack for calling prep_args...
We want the stack to look like this:
[ Previous stack ] <- %r3
[ 64-bytes register save area ] <- %r4
[ Stack space for actual call, passed as ] <- %arg0
[ arg0 to ffi_prep_args_pa32 ]
[ Stack for calling prep_args ] <- %sp
*/
stwm %r1, 64(%sp)
stw %r4, 12(%r3)
L$CFI13
copy %sp, %r4
addl %arg2, %r4, %arg0 ; arg stack
stw %arg3, -48(%r3) ; save flags we need it later
/* Call prep_args:
%arg0(stack) -- set up above
%arg1(ecif) -- same as incoming param
%arg2(bytes) -- same as incoming param */
bl ffi_prep_args_pa32,%r2
ldo 64(%arg0), %sp
ldo -64(%sp), %sp
/* now %sp should point where %arg0 was pointing. */
/* Load the arguments that should be passed in registers
The fp args are loaded by the prep_args function. */
ldw -36(%sp), %arg0
ldw -40(%sp), %arg1
ldw -44(%sp), %arg2
ldw -48(%sp), %arg3
/* in case the function is going to return a structure
we need to give it a place to put the result. */
ldw -52(%r3), %ret0 ; %ret0 <- rvalue
ldw -56(%r3), %r22 ; %r22 <- function to call
bl $$dyncall, %r31 ; Call the user function
copy %r31, %rp
/* Prepare to store the result; we need to recover flags and rvalue. */
ldw -48(%r3), %r21 ; r21 <- flags
ldw -52(%r3), %r20 ; r20 <- rvalue
/* Store the result according to the return type. The most
likely types should come first. */
L$checkint
comib,<>,n FFI_TYPE_INT, %r21, L$checkint8
b L$done
stw %ret0, 0(%r20)
L$checkint8
comib,<>,n FFI_TYPE_UINT8, %r21, L$checkint16
b L$done
stb %ret0, 0(%r20)
L$checkint16
comib,<>,n FFI_TYPE_UINT16, %r21, L$checkdbl
b L$done
sth %ret0, 0(%r20)
L$checkdbl
comib,<>,n FFI_TYPE_DOUBLE, %r21, L$checkfloat
b L$done
fstd %fr4,0(%r20)
L$checkfloat
comib,<>,n FFI_TYPE_FLOAT, %r21, L$checkll
b L$done
fstw %fr4L,0(%r20)
L$checkll
comib,<>,n FFI_TYPE_UINT64, %r21, L$checksmst2
stw %ret0, 0(%r20)
b L$done
stw %ret1, 4(%r20)
L$checksmst2
comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, L$checksmst3
/* 2-byte structs are returned in ret0 as ????xxyy. */
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b L$done
stb %ret0, 0(%r20)
L$checksmst3
comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, L$checksmst4
/* 3-byte structs are returned in ret0 as ??xxyyzz. */
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b L$done
stb %ret0, 0(%r20)
L$checksmst4
comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, L$checksmst5
/* 4-byte structs are returned in ret0 as wwxxyyzz. */
extru %ret0, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b L$done
stb %ret0, 0(%r20)
L$checksmst5
comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, L$checksmst6
/* 5 byte values are returned right justified:
ret0 ret1
5: ??????aa bbccddee */
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b L$done
stb %ret1, 0(%r20)
L$checksmst6
comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, L$checksmst7
/* 6 byte values are returned right justified:
ret0 ret1
6: ????aabb ccddeeff */
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b L$done
stb %ret1, 0(%r20)
L$checksmst7
comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, L$checksmst8
/* 7 byte values are returned right justified:
ret0 ret1
7: ??aabbcc ddeeffgg */
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b L$done
stb %ret1, 0(%r20)
L$checksmst8
comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, L$done
/* 8 byte values are returned right justified:
ret0 ret1
8: aabbccdd eeffgghh */
extru %ret0, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stb %ret1, 0(%r20)
L$done
/* all done, return */
copy %r4, %sp ; pop arg stack
ldw 12(%r3), %r4
ldwm -64(%sp), %r3 ; .. and pop stack
ldw -20(%sp), %rp
bv %r0(%rp)
nop
.exit
.procend
L$FE1
/* void ffi_closure_pa32(void);
Called with closure argument in %r21 */
.SPACE $TEXT$
.SUBSPA $CODE$
.export ffi_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR
.import ffi_closure_inner_pa32,CODE
.align 4
L$FB2
ffi_closure_pa32
.proc
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
.entry
stw %rp, -20(%sp)
copy %r3, %r1
L$CFI21
copy %sp, %r3
L$CFI22
stwm %r1, 64(%sp)
/* Put arguments onto the stack and call ffi_closure_inner. */
stw %arg0, -36(%r3)
stw %arg1, -40(%r3)
stw %arg2, -44(%r3)
stw %arg3, -48(%r3)
copy %r21, %arg0
bl ffi_closure_inner_pa32, %r2
copy %r3, %arg1
ldwm -64(%sp), %r3
ldw -20(%sp), %rp
ldw -36(%sp), %ret0
bv %r0(%rp)
ldw -40(%sp), %ret1
.exit
.procend
L$FE2:
.SPACE $PRIVATE$
.SUBSPA $DATA$
.align 4
.EXPORT _GLOBAL__F_ffi_call_pa32,DATA
_GLOBAL__F_ffi_call_pa32
L$frame1:
.word L$ECIE1-L$SCIE1 ;# Length of Common Information Entry
L$SCIE1:
.word 0x0 ;# CIE Identifier Tag
.byte 0x1 ;# CIE Version
.ascii "\0" ;# CIE Augmentation
.uleb128 0x1 ;# CIE Code Alignment Factor
.sleb128 4 ;# CIE Data Alignment Factor
.byte 0x2 ;# CIE RA Column
.byte 0xc ;# DW_CFA_def_cfa
.uleb128 0x1e
.uleb128 0x0
.align 4
L$ECIE1:
L$SFDE1:
.word L$EFDE1-L$ASFDE1 ;# FDE Length
L$ASFDE1:
.word L$ASFDE1-L$frame1 ;# FDE CIE offset
.word L$FB1 ;# FDE initial location
.word L$FE1-L$FB1 ;# FDE address range
.byte 0x4 ;# DW_CFA_advance_loc4
.word L$CFI11-L$FB1
.byte 0x83 ;# DW_CFA_offset, column 0x3
.uleb128 0x0
.byte 0x11 ;# DW_CFA_offset_extended_sf; save r2 at [r30-20]
.uleb128 0x2
.sleb128 -5
.byte 0x4 ;# DW_CFA_advance_loc4
.word L$CFI12-L$CFI11
.byte 0xd ;# DW_CFA_def_cfa_register = r3
.uleb128 0x3
.byte 0x4 ;# DW_CFA_advance_loc4
.word L$CFI13-L$CFI12
.byte 0x84 ;# DW_CFA_offset, column 0x4
.uleb128 0x3
.align 4
L$EFDE1:
L$SFDE2:
.word L$EFDE2-L$ASFDE2 ;# FDE Length
L$ASFDE2:
.word L$ASFDE2-L$frame1 ;# FDE CIE offset
.word L$FB2 ;# FDE initial location
.word L$FE2-L$FB2 ;# FDE address range
.byte 0x4 ;# DW_CFA_advance_loc4
.word L$CFI21-L$FB2
.byte 0x83 ;# DW_CFA_offset, column 0x3
.uleb128 0x0
.byte 0x11 ;# DW_CFA_offset_extended_sf
.uleb128 0x2
.sleb128 -5
.byte 0x4 ;# DW_CFA_advance_loc4
.word L$CFI22-L$CFI21
.byte 0xd ;# DW_CFA_def_cfa_register = r3
.uleb128 0x3
.align 4
L$EFDE2:

356
libffi/src/pa/linux.S Normal file
View File

@@ -0,0 +1,356 @@
/* -----------------------------------------------------------------------
linux.S - (c) 2003-2004 Randolph Chung <tausq@debian.org>
HPPA 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 <fficonfig.h>
#include <ffi.h>
.text
.level 1.1
.align 4
/* void ffi_call_pa32(void (*)(char *, extended_cif *),
extended_cif *ecif,
unsigned bytes,
unsigned flags,
unsigned *rvalue,
void (*fn)());
*/
.export ffi_call_pa32,code
.import ffi_prep_args_pa32,code
.type ffi_call_pa32, @function
.LFB1:
ffi_call_pa32:
.proc
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
.entry
stw %rp, -20(%sp)
copy %r3, %r1
.LCFI11:
copy %sp, %r3
.LCFI12:
/* Setup the stack for calling prep_args...
We want the stack to look like this:
[ Previous stack ] <- %r3
[ 64-bytes register save area ] <- %r4
[ Stack space for actual call, passed as ] <- %arg0
[ arg0 to ffi_prep_args_pa32 ]
[ Stack for calling prep_args ] <- %sp
*/
stwm %r1, 64(%sp)
stw %r4, 12(%r3)
.LCFI13:
copy %sp, %r4
addl %arg2, %r4, %arg0 /* arg stack */
stw %arg3, -48(%r3) /* save flags; we need it later */
/* Call prep_args:
%arg0(stack) -- set up above
%arg1(ecif) -- same as incoming param
%arg2(bytes) -- same as incoming param */
bl ffi_prep_args_pa32,%r2
ldo 64(%arg0), %sp
ldo -64(%sp), %sp
/* now %sp should point where %arg0 was pointing. */
/* Load the arguments that should be passed in registers
The fp args were loaded by the prep_args function. */
ldw -36(%sp), %arg0
ldw -40(%sp), %arg1
ldw -44(%sp), %arg2
ldw -48(%sp), %arg3
/* in case the function is going to return a structure
we need to give it a place to put the result. */
ldw -52(%r3), %ret0 /* %ret0 <- rvalue */
ldw -56(%r3), %r22 /* %r22 <- function to call */
bl $$dyncall, %r31 /* Call the user function */
copy %r31, %rp
/* Prepare to store the result; we need to recover flags and rvalue. */
ldw -48(%r3), %r21 /* r21 <- flags */
ldw -52(%r3), %r20 /* r20 <- rvalue */
/* Store the result according to the return type. */
.Lcheckint:
comib,<>,n FFI_TYPE_INT, %r21, .Lcheckint8
b .Ldone
stw %ret0, 0(%r20)
.Lcheckint8:
comib,<>,n FFI_TYPE_UINT8, %r21, .Lcheckint16
b .Ldone
stb %ret0, 0(%r20)
.Lcheckint16:
comib,<>,n FFI_TYPE_UINT16, %r21, .Lcheckdbl
b .Ldone
sth %ret0, 0(%r20)
.Lcheckdbl:
comib,<>,n FFI_TYPE_DOUBLE, %r21, .Lcheckfloat
b .Ldone
fstd %fr4,0(%r20)
.Lcheckfloat:
comib,<>,n FFI_TYPE_FLOAT, %r21, .Lcheckll
b .Ldone
fstw %fr4L,0(%r20)
.Lcheckll:
comib,<>,n FFI_TYPE_UINT64, %r21, .Lchecksmst2
stw %ret0, 0(%r20)
b .Ldone
stw %ret1, 4(%r20)
.Lchecksmst2:
comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, .Lchecksmst3
/* 2-byte structs are returned in ret0 as ????xxyy. */
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b .Ldone
stb %ret0, 0(%r20)
.Lchecksmst3:
comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, .Lchecksmst4
/* 3-byte structs are returned in ret0 as ??xxyyzz. */
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b .Ldone
stb %ret0, 0(%r20)
.Lchecksmst4:
comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, .Lchecksmst5
/* 4-byte structs are returned in ret0 as wwxxyyzz. */
extru %ret0, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b .Ldone
stb %ret0, 0(%r20)
.Lchecksmst5:
comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, .Lchecksmst6
/* 5 byte values are returned right justified:
ret0 ret1
5: ??????aa bbccddee */
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b .Ldone
stb %ret1, 0(%r20)
.Lchecksmst6:
comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, .Lchecksmst7
/* 6 byte values are returned right justified:
ret0 ret1
6: ????aabb ccddeeff */
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b .Ldone
stb %ret1, 0(%r20)
.Lchecksmst7:
comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, .Lchecksmst8
/* 7 byte values are returned right justified:
ret0 ret1
7: ??aabbcc ddeeffgg */
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
b .Ldone
stb %ret1, 0(%r20)
.Lchecksmst8:
comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, .Ldone
/* 8 byte values are returned right justified:
ret0 ret1
8: aabbccdd eeffgghh */
extru %ret0, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret0, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stbs,ma %ret0, 1(%r20)
extru %ret1, 7, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 15, 8, %r22
stbs,ma %r22, 1(%r20)
extru %ret1, 23, 8, %r22
stbs,ma %r22, 1(%r20)
stb %ret1, 0(%r20)
.Ldone:
/* all done, return */
copy %r4, %sp /* pop arg stack */
ldw 12(%r3), %r4
ldwm -64(%sp), %r3 /* .. and pop stack */
ldw -20(%sp), %rp
bv %r0(%rp)
nop
.exit
.procend
.LFE1:
/* void ffi_closure_pa32(void);
Called with closure argument in %r21 */
.export ffi_closure_pa32,code
.import ffi_closure_inner_pa32,code
.type ffi_closure_pa32, @function
.LFB2:
ffi_closure_pa32:
.proc
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
.entry
stw %rp, -20(%sp)
.LCFI20:
copy %r3, %r1
.LCFI21:
copy %sp, %r3
.LCFI22:
stwm %r1, 64(%sp)
/* Put arguments onto the stack and call ffi_closure_inner. */
stw %arg0, -36(%r3)
stw %arg1, -40(%r3)
stw %arg2, -44(%r3)
stw %arg3, -48(%r3)
copy %r21, %arg0
bl ffi_closure_inner_pa32, %r2
copy %r3, %arg1
ldwm -64(%sp), %r3
ldw -20(%sp), %rp
ldw -36(%sp), %ret0
bv %r0(%r2)
ldw -40(%sp), %ret1
.exit
.procend
.LFE2:
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
.Lframe1:
.word .LECIE1-.LSCIE1 ;# Length of Common Information Entry
.LSCIE1:
.word 0x0 ;# CIE Identifier Tag
.byte 0x1 ;# CIE Version
.ascii "\0" ;# CIE Augmentation
.uleb128 0x1 ;# CIE Code Alignment Factor
.sleb128 4 ;# CIE Data Alignment Factor
.byte 0x2 ;# CIE RA Column
.byte 0xc ;# DW_CFA_def_cfa
.uleb128 0x1e
.uleb128 0x0
.align 4
.LECIE1:
.LSFDE1:
.word .LEFDE1-.LASFDE1 ;# FDE Length
.LASFDE1:
.word .LASFDE1-.Lframe1 ;# FDE CIE offset
.word .LFB1 ;# FDE initial location
.word .LFE1-.LFB1 ;# FDE address range
.byte 0x4 ;# DW_CFA_advance_loc4
.word .LCFI11-.LFB1
.byte 0x83 ;# DW_CFA_offset, column 0x3
.uleb128 0x0
.byte 0x11 ;# DW_CFA_offset_extended_sf; save r2 at [r30-20]
.uleb128 0x2
.sleb128 -5
.byte 0x4 ;# DW_CFA_advance_loc4
.word .LCFI12-.LCFI11
.byte 0xd ;# DW_CFA_def_cfa_register = r3
.uleb128 0x3
.byte 0x4 ;# DW_CFA_advance_loc4
.word .LCFI13-.LCFI12
.byte 0x84 ;# DW_CFA_offset, column 0x4
.uleb128 0x3
.align 4
.LEFDE1:
.LSFDE2:
.word .LEFDE2-.LASFDE2 ;# FDE Length
.LASFDE2:
.word .LASFDE2-.Lframe1 ;# FDE CIE offset
.word .LFB2 ;# FDE initial location
.word .LFE2-.LFB2 ;# FDE address range
.byte 0x4 ;# DW_CFA_advance_loc4
.word .LCFI21-.LFB2
.byte 0x83 ;# DW_CFA_offset, column 0x3
.uleb128 0x0
.byte 0x11 ;# DW_CFA_offset_extended_sf
.uleb128 0x2
.sleb128 -5
.byte 0x4 ;# DW_CFA_advance_loc4
.word .LCFI22-.LCFI21
.byte 0xd ;# DW_CFA_def_cfa_register = r3
.uleb128 0x3
.align 4
.LEFDE2:

225
libffi/src/powerpc/aix.S Normal file
View File

@@ -0,0 +1,225 @@
/* -----------------------------------------------------------------------
aix.S - Copyright (c) 2002 Free Software Foundation, Inc.
based on darwin.S by John Hornkvist
PowerPC Assembly glue.
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.
----------------------------------------------------------------------- */
.set r0,0
.set r1,1
.set r2,2
.set r3,3
.set r4,4
.set r5,5
.set r6,6
.set r7,7
.set r8,8
.set r9,9
.set r10,10
.set r11,11
.set r12,12
.set r13,13
.set r14,14
.set r15,15
.set r16,16
.set r17,17
.set r18,18
.set r19,19
.set r20,20
.set r21,21
.set r22,22
.set r23,23
.set r24,24
.set r25,25
.set r26,26
.set r27,27
.set r28,28
.set r29,29
.set r30,30
.set r31,31
.set f0,0
.set f1,1
.set f2,2
.set f3,3
.set f4,4
.set f5,5
.set f6,6
.set f7,7
.set f8,8
.set f9,9
.set f10,10
.set f11,11
.set f12,12
.set f13,13
.set f14,14
.set f15,15
.set f16,16
.set f17,17
.set f18,18
.set f19,19
.set f20,20
.set f21,21
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#define JUMPTARGET(name) name
#define L(x) x
.file "aix.S"
.toc
.csect .text[PR]
.align 2
.globl ffi_prep_args
.csect .text[PR]
.align 2
.globl ffi_call_AIX
.globl .ffi_call_AIX
.csect ffi_call_AIX[DS]
ffi_call_AIX:
.long .ffi_call_AIX, TOC[tc0], 0
.csect .text[PR]
.ffi_call_AIX:
mr r12,r8 // We only need r12 until the call, so it doesn't have to be saved...
/* Save the old stack pointer as AP. */
mr r8,r1
/* Allocate the stack space we need. */
stwux r1,r1,r4
/* Save registers we use. */
mflr r9
stw r28,-16(r8)
stw r29,-12(r8)
stw r30, -8(r8)
stw r31, -4(r8)
stw r9, 8(r8)
stw r2, 20(r1)
/* Save arguments over call... */
mr r31,r5 /* flags, */
mr r30,r6 /* rvalue, */
mr r29,r7 /* function address, */
mr r28,r8 /* our AP. */
/* Call ffi_prep_args. */
mr r4,r1
li r9,0
lwz r2,4(r12)
lwz r12,0(r12)
mtctr r12 // r12 holds address of _ffi_prep_args
bctrl
lwz r2,20(r1)
/* Now do the call. */
lwz r12,0(r29)
/* Set up cr1 with bits 4-7 of the flags. */
mtcrf 0x40,r31
stw r2,20(r1)
mtctr r12
lwz r2,4(r29)
/* Load all those argument registers. */
// We have set up a nice stack frame, just load it into registers.
lwz r3, 20+(1*4)(r1)
lwz r4, 20+(2*4)(r1)
lwz r5, 20+(3*4)(r1)
lwz r6, 20+(4*4)(r1)
nop
lwz r7, 20+(5*4)(r1)
lwz r8, 20+(6*4)(r1)
lwz r9, 20+(7*4)(r1)
lwz r10,20+(8*4)(r1)
L1:
/* Load all the FP registers. */
bf 6,L2 // 2f + 0x18
lfd f1,-16-(13*8)(r28)
lfd f2,-16-(12*8)(r28)
lfd f3,-16-(11*8)(r28)
lfd f4,-16-(10*8)(r28)
nop
lfd f5,-16-(9*8)(r28)
lfd f6,-16-(8*8)(r28)
lfd f7,-16-(7*8)(r28)
lfd f8,-16-(6*8)(r28)
nop
lfd f9,-16-(5*8)(r28)
lfd f10,-16-(4*8)(r28)
lfd f11,-16-(3*8)(r28)
lfd f12,-16-(2*8)(r28)
nop
lfd f13,-16-(1*8)(r28)
L2:
/* Make the call. */
bctrl
lwz r2,20(r1)
/* Now, deal with the return value. */
mtcrf 0x01,r31
bt 30,L(done_return_value)
bt 29,L(fp_return_value)
stw r3,0(r30)
bf 28,L(done_return_value)
stw r4,4(r30)
/* Fall through... */
L(done_return_value):
/* Restore the registers we used and return. */
lwz r9, 8(r28)
lwz r31, -4(r28)
mtlr r9
lwz r30, -8(r28)
lwz r29,-12(r28)
lwz r28,-16(r28)
lwz r1,0(r1)
blr
L(fp_return_value):
bf 28,L(float_return_value)
stfd f1,0(r30)
b L(done_return_value)
L(float_return_value):
stfs f1,0(r30)
b L(done_return_value)
.long 0
.byte 0,0,0,1,128,4,0,0
//END(ffi_call_AIX)
.csect .text[PR]
.align 2
.globl ffi_call_DARWIN
.globl .ffi_call_DARWIN
.csect ffi_call_DARWIN[DS]
ffi_call_DARWIN:
.long .ffi_call_DARWIN, TOC[tc0], 0
.csect .text[PR]
.ffi_call_DARWIN:
blr
.long 0
.byte 0,0,0,0,0,0,0,0
//END(ffi_call_DARWIN)

View File

@@ -0,0 +1,247 @@
/* -----------------------------------------------------------------------
aix_closure.S - Copyright (c) 2002 2003 Free Software Foundation, Inc.
based on darwin_closure.S
PowerPC Assembly glue.
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.
----------------------------------------------------------------------- */
.set r0,0
.set r1,1
.set r2,2
.set r3,3
.set r4,4
.set r5,5
.set r6,6
.set r7,7
.set r8,8
.set r9,9
.set r10,10
.set r11,11
.set r12,12
.set r13,13
.set r14,14
.set r15,15
.set r16,16
.set r17,17
.set r18,18
.set r19,19
.set r20,20
.set r21,21
.set r22,22
.set r23,23
.set r24,24
.set r25,25
.set r26,26
.set r27,27
.set r28,28
.set r29,29
.set r30,30
.set r31,31
.set f0,0
.set f1,1
.set f2,2
.set f3,3
.set f4,4
.set f5,5
.set f6,6
.set f7,7
.set f8,8
.set f9,9
.set f10,10
.set f11,11
.set f12,12
.set f13,13
.set f14,14
.set f15,15
.set f16,16
.set f17,17
.set f18,18
.set f19,19
.set f20,20
.set f21,21
#define LIBFFI_ASM
#define JUMPTARGET(name) name
#define L(x) x
.file "aix_closure.S"
.toc
LC..60:
.tc L..60[TC],L..60
.csect .text[PR]
.align 2
.csect .text[PR]
.align 2
.globl ffi_closure_ASM
.globl .ffi_closure_ASM
.csect ffi_closure_ASM[DS]
ffi_closure_ASM:
.long .ffi_closure_ASM, TOC[tc0], 0
.csect .text[PR]
.ffi_closure_ASM:
mflr r0 /* extract return address */
stw r0, 8(r1) /* save the return address */
/* 24 Bytes (Linkage Area) */
/* 32 Bytes (params) */
/* 104 Bytes (13*8 from FPR) */
/* 8 Bytes (result) */
/* 168 Bytes */
stwu r1,-176(r1) /* skip over caller save area
keep stack aligned to 16 */
/* we want to build up an area for the parameters passed */
/* in registers (both floating point and integer) */
/* we store gpr 3 to gpr 10 (aligned to 4)
in the parents outgoing area */
stw r3, 200(r1)
stw r4, 204(r1)
stw r5, 208(r1)
stw r6, 212(r1)
stw r7, 216(r1)
stw r8, 220(r1)
stw r9, 224(r1)
stw r10, 228(r1)
/* next save fpr 1 to fpr 13 (aligned to 8) */
stfd f1, 56(r1)
stfd f2, 64(r1)
stfd f3, 72(r1)
stfd f4, 80(r1)
stfd f5, 88(r1)
stfd f6, 96(r1)
stfd f7, 104(r1)
stfd f8, 112(r1)
stfd f9, 120(r1)
stfd f10, 128(r1)
stfd f11, 136(r1)
stfd f12, 144(r1)
stfd f13, 152(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,160
/* now load up the pointer to the saved gpr registers */
addi r5,r1,200
/* now load up the pointer to the saved fpr registers */
addi r6,r1,56
/* make the call */
bl .ffi_closure_helper_DARWIN
nop
/* 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,160 /* get pointer to results area */
lwz r4,LC..60(2) /* get address of jump table */
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 */
L..60:
.long L..44-L..60 /* FFI_TYPE_VOID */
.long L..50-L..60 /* FFI_TYPE_INT */
.long L..47-L..60 /* FFI_TYPE_FLOAT */
.long L..46-L..60 /* FFI_TYPE_DOUBLE */
.long L..46-L..60 /* FFI_TYPE_LONGDOUBLE */
.long L..56-L..60 /* FFI_TYPE_UINT8 */
.long L..55-L..60 /* FFI_TYPE_SINT8 */
.long L..58-L..60 /* FFI_TYPE_UINT16 */
.long L..57-L..60 /* FFI_TYPE_SINT16 */
.long L..50-L..60 /* FFI_TYPE_UINT32 */
.long L..50-L..60 /* FFI_TYPE_SINT32 */
.long L..48-L..60 /* FFI_TYPE_UINT64 */
.long L..48-L..60 /* FFI_TYPE_SINT64 */
.long L..44-L..60 /* FFI_TYPE_STRUCT */
.long L..50-L..60 /* FFI_TYPE_POINTER */
/* case double */
L..46:
lfd f1,0(r5)
b L..44
/* case float */
L..47:
lfs f1,0(r5)
b L..44
/* case long long */
L..48:
lwz r3,0(r5)
lwz r4,4(r5)
b L..44
/* case default / int32 / pointer */
L..50:
lwz r3,0(r5)
b L..44
/* case signed int8 */
L..55:
addi r5,r5,3
lbz r3,0(r5)
slwi r3,r3,24
srawi r3,r3,24
b L..44
/* case unsigned int8 */
L..56:
addi r5,r5,3
lbz r3,0(r5)
b L..44
/* case signed int16 */
L..57:
addi r5,r5,2
lhz r3,0(r5)
extsh r3,r3
b L..44
/* case unsigned int16 */
L..58:
addi r5,r5,2
lhz r3,0(r5)
/* case void / done */
L..44:
addi r1,r1,176 /* restore stack pointer */
lwz r0,8(r1) /* get return address */
mtlr r0 /* reset link register */
blr
/* END(ffi_closure_ASM) */

125
libffi/src/powerpc/asm.h Normal file
View File

@@ -0,0 +1,125 @@
/* -----------------------------------------------------------------------
asm.h - Copyright (c) 1998 Geoffrey Keating
PowerPC Assembly glue.
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.
----------------------------------------------------------------------- */
#define ASM_GLOBAL_DIRECTIVE .globl
#define C_SYMBOL_NAME(name) name
/* Macro for a label. */
#ifdef __STDC__
#define C_LABEL(name) name##:
#else
#define C_LABEL(name) name/**/:
#endif
/* This seems to always be the case on PPC. */
#define ALIGNARG(log2) log2
/* For ELF we need the `.type' directive to make shared libs work right. */
#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
/* If compiled for profiling, call `_mcount' at the start of each function. */
#ifdef PROF
/* The mcount code relies on a the return address being on the stack
to locate our caller and so it can restore it; so store one just
for its benefit. */
#ifdef PIC
#define CALL_MCOUNT \
.pushsection; \
.section ".data"; \
.align ALIGNARG(2); \
0:.long 0; \
.previous; \
mflr %r0; \
stw %r0,4(%r1); \
bl _GLOBAL_OFFSET_TABLE_@local-4; \
mflr %r11; \
lwz %r0,0b@got(%r11); \
bl JUMPTARGET(_mcount);
#else /* PIC */
#define CALL_MCOUNT \
.section ".data"; \
.align ALIGNARG(2); \
0:.long 0; \
.previous; \
mflr %r0; \
lis %r11,0b@ha; \
stw %r0,4(%r1); \
addi %r0,%r11,0b@l; \
bl JUMPTARGET(_mcount);
#endif /* PIC */
#else /* PROF */
#define CALL_MCOUNT /* Do nothing. */
#endif /* PROF */
#define ENTRY(name) \
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
.align ALIGNARG(2); \
C_LABEL(name) \
CALL_MCOUNT
#define EALIGN_W_0 /* No words to insert. */
#define EALIGN_W_1 nop
#define EALIGN_W_2 nop;nop
#define EALIGN_W_3 nop;nop;nop
#define EALIGN_W_4 EALIGN_W_3;nop
#define EALIGN_W_5 EALIGN_W_4;nop
#define EALIGN_W_6 EALIGN_W_5;nop
#define EALIGN_W_7 EALIGN_W_6;nop
/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes
past a 2^align boundary. */
#ifdef PROF
#define EALIGN(name, alignt, words) \
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
.align ALIGNARG(2); \
C_LABEL(name) \
CALL_MCOUNT \
b 0f; \
.align ALIGNARG(alignt); \
EALIGN_W_##words; \
0:
#else /* PROF */
#define EALIGN(name, alignt, words) \
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
.align ALIGNARG(alignt); \
EALIGN_W_##words; \
C_LABEL(name)
#endif
#define END(name) \
ASM_SIZE_DIRECTIVE(name)
#ifdef PIC
#define JUMPTARGET(name) name##@plt
#else
#define JUMPTARGET(name) name
#endif
/* Local labels stripped out by the linker. */
#define L(x) .L##x

245
libffi/src/powerpc/darwin.S Normal file
View File

@@ -0,0 +1,245 @@
/* -----------------------------------------------------------------------
darwin.S - Copyright (c) 2000 John Hornkvist
Copyright (c) 2004 Free Software Foundation, Inc.
PowerPC Assembly glue.
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.
----------------------------------------------------------------------- */
#if defined(__ppc64__)
#define MODE_CHOICE(x, y) y
#else
#define MODE_CHOICE(x, y) x
#endif
#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */
#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#define JUMPTARGET(name) name
#define L(x) x
.text
.align 2
.globl _ffi_prep_args
.text
.align 2
.globl _ffi_call_DARWIN
.text
.align 2
_ffi_call_DARWIN:
LFB0:
mr r12,r8 /* We only need r12 until the call,
so it doesn't have to be saved. */
LFB1:
/* Save the old stack pointer as AP. */
mr r8,r1
LCFI0:
/* Allocate the stack space we need. */
stwux r1,r1,r4
/* Save registers we use. */
mflr r9
stw r28,-16(r8)
stw r29,-12(r8)
stw r30,-8(r8)
stw r31,-4(r8)
stw r9,8(r8)
stw r2,20(r1)
LCFI1:
/* Save arguments over call. */
mr r31,r5 /* flags, */
mr r30,r6 /* rvalue, */
mr r29,r7 /* function address, */
mr r28,r8 /* our AP. */
LCFI2:
/* Call ffi_prep_args. */
mr r4,r1
li r9,0
mtctr r12 /* r12 holds address of _ffi_prep_args. */
bctrl
lwz r2,20(r1)
/* Now do the call.
Set up cr1 with bits 4-7 of the flags. */
mtcrf 0x40,r31
/* Get the address to call into CTR. */
mtctr r29
/* Load all those argument registers.
We have set up a nice stack frame, just load it into registers. */
lwz r3,20+(1*4)(r1)
lwz r4,20+(2*4)(r1)
lwz r5,20+(3*4)(r1)
lwz r6,20+(4*4)(r1)
nop
lwz r7,20+(5*4)(r1)
lwz r8,20+(6*4)(r1)
lwz r9,20+(7*4)(r1)
lwz r10,20+(8*4)(r1)
L1:
/* Load all the FP registers. */
bf 6,L2 /* No floats to load. */
lfd f1,-16-(13*8)(r28)
lfd f2,-16-(12*8)(r28)
lfd f3,-16-(11*8)(r28)
lfd f4,-16-(10*8)(r28)
nop
lfd f5,-16-(9*8)(r28)
lfd f6,-16-(8*8)(r28)
lfd f7,-16-(7*8)(r28)
lfd f8,-16-(6*8)(r28)
nop
lfd f9,-16-(5*8)(r28)
lfd f10,-16-(4*8)(r28)
lfd f11,-16-(3*8)(r28)
lfd f12,-16-(2*8)(r28)
nop
lfd f13,-16-(1*8)(r28)
L2:
mr r12,r29 /* Put the target address in r12 as specified. */
mtctr r12
nop
nop
/* Make the call. */
bctrl
/* Now, deal with the return value. */
mtcrf 0x01,r31
bt 30,L(done_return_value)
bt 29,L(fp_return_value)
stw r3,0(r30)
bf 28,L(done_return_value)
stw r4,4(r30)
/* Fall through. */
L(done_return_value):
/* Restore the registers we used and return. */
lwz r9,8(r28)
lwz r31,-4(r28)
mtlr r9
lwz r30,-8(r28)
lwz r29,-12(r28)
lwz r28,-16(r28)
lwz r1,0(r1)
blr
L(fp_return_value):
/* Do we have long double to store? */
bf 31,L(fd_return_value)
stfd f1,0(r30)
stfd f2,8(r30)
b L(done_return_value)
L(fd_return_value):
/* Do we have double to store? */
bf 28,L(float_return_value)
stfd f1,0(r30)
b L(done_return_value)
L(float_return_value):
/* We only have a float to store. */
stfs f1,0(r30)
b L(done_return_value)
LFE1:
/* END(_ffi_call_DARWIN) */
/* Provide a null definition of _ffi_call_AIX. */
.text
.align 2
.globl _ffi_call_AIX
.text
.align 2
_ffi_call_AIX:
blr
/* END(_ffi_call_AIX) */
.data
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 ; Length of Common Information Entry
LSCIE1:
.long 0x0 ; CIE Identifier Tag
.byte 0x1 ; CIE Version
.ascii "zR\0" ; CIE Augmentation
.byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c ; sleb128 -4; CIE Data Alignment Factor
.byte 0x41 ; CIE RA Column
.byte 0x1 ; uleb128 0x1; Augmentation size
.byte 0x90 ; FDE Encoding (indirect pcrel)
.byte 0xc ; DW_CFA_def_cfa
.byte 0x1 ; uleb128 0x1
.byte 0x0 ; uleb128 0x0
.align LOG2_GPR_BYTES
LECIE1:
.globl _ffi_call_DARWIN.eh
_ffi_call_DARWIN.eh:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1
.long L$set$1 ; FDE Length
LASFDE1:
.long LASFDE1-EH_frame1 ; FDE CIE offset
.g_long LLFB0$non_lazy_ptr-. ; FDE initial location
.set L$set$3,LFE1-LFB0
.g_long L$set$3 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$4,LCFI0-LFB1
.long L$set$4
.byte 0xd ; DW_CFA_def_cfa_register
.byte 0x08 ; uleb128 0x08
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$5,LCFI1-LCFI0
.long L$set$5
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x41 ; uleb128 0x41
.byte 0x7e ; sleb128 -2
.byte 0x9f ; DW_CFA_offset, column 0x1f
.byte 0x1 ; uleb128 0x1
.byte 0x9e ; DW_CFA_offset, column 0x1e
.byte 0x2 ; uleb128 0x2
.byte 0x9d ; DW_CFA_offset, column 0x1d
.byte 0x3 ; uleb128 0x3
.byte 0x9c ; DW_CFA_offset, column 0x1c
.byte 0x4 ; uleb128 0x4
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$6,LCFI2-LCFI1
.long L$set$6
.byte 0xd ; DW_CFA_def_cfa_register
.byte 0x1c ; uleb128 0x1c
.align LOG2_GPR_BYTES
LEFDE1:
.data
.align LOG2_GPR_BYTES
LLFB0$non_lazy_ptr:
.g_long LFB0

View File

@@ -0,0 +1,317 @@
/* -----------------------------------------------------------------------
darwin_closure.S - Copyright (c) 2002, 2003, 2004, Free Software Foundation,
Inc. based on ppc_closure.S
PowerPC Assembly glue.
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.
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#define L(x) x
#if defined(__ppc64__)
#define MODE_CHOICE(x, y) y
#else
#define MODE_CHOICE(x, y) x
#endif
#define lgu MODE_CHOICE(lwzu, ldu)
#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */
#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */
.file "darwin_closure.S"
.text
.align LOG2_GPR_BYTES
.globl _ffi_closure_ASM
.text
.align LOG2_GPR_BYTES
_ffi_closure_ASM:
LFB1:
mflr r0 /* extract return address */
stw r0,8(r1) /* save the return address */
LCFI0:
/* 24 Bytes (Linkage Area)
32 Bytes (outgoing parameter area, always reserved)
104 Bytes (13*8 from FPR)
16 Bytes (result)
176 Bytes */
stwu r1,-176(r1) /* skip over caller save area
keep stack aligned to 16. */
LCFI1:
/* We want to build up an area for the parameters passed
in registers. (both floating point and integer) */
/* We store gpr 3 to gpr 10 (aligned to 4)
in the parents outgoing area. */
stw r3,200(r1)
stw r4,204(r1)
stw r5,208(r1)
stw r6,212(r1)
stw r7,216(r1)
stw r8,220(r1)
stw r9,224(r1)
stw r10,228(r1)
/* We save fpr 1 to fpr 13. (aligned to 8) */
stfd f1,56(r1)
stfd f2,64(r1)
stfd f3,72(r1)
stfd f4,80(r1)
stfd f5,88(r1)
stfd f6,96(r1)
stfd f7,104(r1)
stfd f8,112(r1)
stfd f9,120(r1)
stfd f10,128(r1)
stfd f11,136(r1)
stfd f12,144(r1)
stfd f13,152(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,160
/* Now load up the pointer to the saved gpr registers. */
addi r5,r1,200
/* Now load up the pointer to the saved fpr registers. */
addi r6,r1,56
/* Make the call. */
bl Lffi_closure_helper_DARWIN$stub
/* 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,160 /* Get pointer to results area. */
bl Lget_ret_type0_addr /* Get pointer to Lret_type0 into LR. */
mflr r4 /* Move to r4. */
slwi r3,r3,4 /* Now multiply return type by 16. */
add r3,r3,r4 /* Add contents of table to table address. */
mtctr r3
bctr /* Jump to it. */
LFE1:
/* Each of the ret_typeX code fragments has to be exactly 16 bytes long
(4 instructions). For cache effectiveness we align to a 16 byte boundary
first. */
.align 4
nop
nop
nop
Lget_ret_type0_addr:
blrl
/* case FFI_TYPE_VOID */
Lret_type0:
b Lfinish
nop
nop
nop
/* case FFI_TYPE_INT */
Lret_type1:
lwz r3,0(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_FLOAT */
Lret_type2:
lfs f1,0(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_DOUBLE */
Lret_type3:
lfd f1,0(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_LONGDOUBLE */
Lret_type4:
lfd f1,0(r5)
lfd f2,8(r5)
b Lfinish
nop
/* case FFI_TYPE_UINT8 */
Lret_type5:
lbz r3,3(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_SINT8 */
Lret_type6:
lbz r3,3(r5)
extsb r3,r3
b Lfinish
nop
/* case FFI_TYPE_UINT16 */
Lret_type7:
lhz r3,2(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_SINT16 */
Lret_type8:
lha r3,2(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_UINT32 */
Lret_type9:
lwz r3,0(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_SINT32 */
Lret_type10:
lwz r3,0(r5)
b Lfinish
nop
nop
/* case FFI_TYPE_UINT64 */
Lret_type11:
lwz r3,0(r5)
lwz r4,4(r5)
b Lfinish
nop
/* case FFI_TYPE_SINT64 */
Lret_type12:
lwz r3,0(r5)
lwz r4,4(r5)
b Lfinish
nop
/* case FFI_TYPE_STRUCT */
Lret_type13:
b Lfinish
nop
nop
nop
/* case FFI_TYPE_POINTER */
Lret_type14:
lwz r3,0(r5)
b Lfinish
nop
nop
/* case done */
Lfinish:
addi r1,r1,176 /* Restore stack pointer. */
lwz r0,8(r1) /* Get return address. */
mtlr r0 /* Reset link register. */
blr
/* END(ffi_closure_ASM) */
.data
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 ; Length of Common Information Entry
LSCIE1:
.long 0x0 ; CIE Identifier Tag
.byte 0x1 ; CIE Version
.ascii "zR\0" ; CIE Augmentation
.byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c ; sleb128 -4; CIE Data Alignment Factor
.byte 0x41 ; CIE RA Column
.byte 0x1 ; uleb128 0x1; Augmentation size
.byte 0x90 ; FDE Encoding (indirect pcrel)
.byte 0xc ; DW_CFA_def_cfa
.byte 0x1 ; uleb128 0x1
.byte 0x0 ; uleb128 0x0
.align LOG2_GPR_BYTES
LECIE1:
.globl _ffi_closure_ASM.eh
_ffi_closure_ASM.eh:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1
.long L$set$1 ; FDE Length
LASFDE1:
.long LASFDE1-EH_frame1 ; FDE CIE offset
.g_long LLFB1$non_lazy_ptr-. ; FDE initial location
.set L$set$3,LFE1-LFB1
.g_long L$set$3 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$3,LCFI1-LCFI0
.long L$set$3
.byte 0xe ; DW_CFA_def_cfa_offset
.byte 176,1 ; uleb128 176
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$4,LCFI0-LFB1
.long L$set$4
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x41 ; uleb128 0x41
.byte 0x7e ; sleb128 -2
.align LOG2_GPR_BYTES
LEFDE1:
.data
.align LOG2_GPR_BYTES
LDFCM0:
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align LOG2_GPR_BYTES
Lffi_closure_helper_DARWIN$stub:
#if 1
.indirect_symbol _ffi_closure_helper_DARWIN
mflr r0
bcl 20,31,LO$ffi_closure_helper_DARWIN
LO$ffi_closure_helper_DARWIN:
mflr r11
addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)
mtlr r0
lgu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)(r11)
mtctr r12
bctr
.lazy_symbol_pointer
L_ffi_closure_helper_DARWIN$lazy_ptr:
.indirect_symbol _ffi_closure_helper_DARWIN
.g_long dyld_stub_binding_helper
#endif
.data
.align LOG2_GPR_BYTES
LLFB1$non_lazy_ptr:
.g_long LFB1

1298
libffi/src/powerpc/ffi.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,799 @@
/* -----------------------------------------------------------------------
ffi_darwin.c
Copyright (C) 1998 Geoffrey Keating
Copyright (C) 2001 John Hornkvist
Copyright (C) 2002, 2006 Free Software Foundation, Inc.
FFI support for Darwin and AIX.
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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
extern void ffi_closure_ASM(void);
enum {
/* The assembly depends on these exact flags. */
FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
FLAG_RETURNS_FP = 1 << (31-29),
FLAG_RETURNS_64BITS = 1 << (31-28),
FLAG_RETURNS_128BITS = 1 << (31-31),
FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
FLAG_RETVAL_REFERENCE = 1 << (31- 4)
};
/* About the DARWIN ABI. */
enum {
NUM_GPR_ARG_REGISTERS = 8,
NUM_FPR_ARG_REGISTERS = 13
};
enum { ASM_NEEDS_REGISTERS = 4 };
/* 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:
| Return address from ffi_call_DARWIN | higher addresses
|--------------------------------------------|
| Previous backchain pointer 4 | stack pointer here
|--------------------------------------------|<+ <<< on entry to
| Saved r28-r31 4*4 | | ffi_call_DARWIN
|--------------------------------------------| |
| Parameters (at least 8*4=32) | |
|--------------------------------------------| |
| Space for GPR2 4 | |
|--------------------------------------------| | stack |
| Reserved 2*4 | | grows |
|--------------------------------------------| | down V
| Space for callee's LR 4 | |
|--------------------------------------------| | lower addresses
| Saved CR 4 | |
|--------------------------------------------| | stack pointer here
| Current backchain pointer 4 |-/ during
|--------------------------------------------| <<< ffi_call_DARWIN
*/
void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
{
const unsigned bytes = ecif->cif->bytes;
const unsigned flags = ecif->cif->flags;
/* 'stacktop' points at the previous backchain pointer. */
unsigned *const stacktop = stack + (bytes / sizeof(unsigned));
/* 'fpr_base' points at the space for fpr1, and grows upwards as
we use FPR registers. */
double *fpr_base = (double*) (stacktop - ASM_NEEDS_REGISTERS) - NUM_FPR_ARG_REGISTERS;
int fparg_count = 0;
/* 'next_arg' grows up as we put parameters in it. */
unsigned *next_arg = stack + 6; /* 6 reserved positions. */
int i = ecif->cif->nargs;
double double_tmp;
void **p_argv = ecif->avalue;
unsigned gprvalue;
ffi_type** ptr = ecif->cif->arg_types;
char *dest_cpy;
unsigned size_al = 0;
/* Check that everything starts aligned properly. */
FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
FFI_ASSERT((bytes & 0xF) == 0);
/* Deal with return values that are actually pass-by-reference.
Rule:
Return values are referenced by r3, so r4 is the first parameter. */
if (flags & FLAG_RETVAL_REFERENCE)
*next_arg++ = (unsigned)(char *)ecif->rvalue;
/* Now for the arguments. */
for (;
i > 0;
i--, ptr++, p_argv++)
{
switch ((*ptr)->type)
{
/* If a floating-point parameter appears before all of the general-
purpose registers are filled, the corresponding GPRs that match
the size of the floating-point parameter are skipped. */
case FFI_TYPE_FLOAT:
double_tmp = *(float *)*p_argv;
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
*(double *)next_arg = double_tmp;
else
*fpr_base++ = double_tmp;
next_arg++;
fparg_count++;
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
break;
case FFI_TYPE_DOUBLE:
double_tmp = *(double *)*p_argv;
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
*(double *)next_arg = double_tmp;
else
*fpr_base++ = double_tmp;
next_arg += 2;
fparg_count++;
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
double_tmp = ((double *)*p_argv)[0];
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
*(double *)next_arg = double_tmp;
else
*fpr_base++ = double_tmp;
next_arg += 2;
fparg_count++;
double_tmp = ((double *)*p_argv)[1];
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
*(double *)next_arg = double_tmp;
else
*fpr_base++ = double_tmp;
next_arg += 2;
fparg_count++;
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
break;
#endif
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
*(long long *)next_arg = *(long long *)*p_argv;
next_arg+=2;
break;
case FFI_TYPE_UINT8:
gprvalue = *(unsigned char *)*p_argv;
goto putgpr;
case FFI_TYPE_SINT8:
gprvalue = *(signed char *)*p_argv;
goto putgpr;
case FFI_TYPE_UINT16:
gprvalue = *(unsigned short *)*p_argv;
goto putgpr;
case FFI_TYPE_SINT16:
gprvalue = *(signed short *)*p_argv;
goto putgpr;
case FFI_TYPE_STRUCT:
dest_cpy = (char *) next_arg;
/* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
SI 4 bytes) are aligned as if they were those modes.
Structures with 3 byte in size are padded upwards. */
size_al = (*ptr)->size;
/* If the first member of the struct is a double, then align
the struct to double-word.
Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */
if ((*ptr)->elements[0]->type == 3)
size_al = ALIGN((*ptr)->size, 8);
if (size_al < 3 && ecif->cif->abi == FFI_DARWIN)
dest_cpy += 4 - size_al;
memcpy((char *)dest_cpy, (char *)*p_argv, size_al);
next_arg += (size_al + 3) / 4;
break;
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
gprvalue = *(unsigned *)*p_argv;
putgpr:
*next_arg++ = gprvalue;
break;
default:
break;
}
}
/* Check that we didn't overrun the stack... */
//FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
//FFI_ASSERT((unsigned *)fpr_base
// <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
//FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
}
/* Adjust the size of S to be correct for Darwin.
On Darwin, the first field of a structure has natural alignment. */
static void
darwin_adjust_aggregate_sizes (ffi_type *s)
{
int i;
if (s->type != FFI_TYPE_STRUCT)
return;
s->size = 0;
for (i = 0; s->elements[i] != NULL; i++)
{
ffi_type *p;
int align;
p = s->elements[i];
darwin_adjust_aggregate_sizes (p);
if (i == 0
&& (p->type == FFI_TYPE_UINT64
|| p->type == FFI_TYPE_SINT64
|| p->type == FFI_TYPE_DOUBLE
|| p->alignment == 8))
align = 8;
else if (p->alignment == 16 || p->alignment < 4)
align = p->alignment;
else
align = 4;
s->size = ALIGN(s->size, align) + p->size;
}
s->size = ALIGN(s->size, s->alignment);
if (s->elements[0]->type == FFI_TYPE_UINT64
|| s->elements[0]->type == FFI_TYPE_SINT64
|| s->elements[0]->type == FFI_TYPE_DOUBLE
|| s->elements[0]->alignment == 8)
s->alignment = s->alignment > 8 ? s->alignment : 8;
/* Do not add additional tail padding. */
}
/* Perform machine dependent cif processing. */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* All this is for the DARWIN ABI. */
int i;
ffi_type **ptr;
unsigned bytes;
int fparg_count = 0, intarg_count = 0;
unsigned flags = 0;
unsigned size_al = 0;
/* All the machine-independent calculation of cif->bytes will be wrong.
All the calculation of structure sizes will also be wrong.
Redo the calculation for DARWIN. */
if (cif->abi == FFI_DARWIN)
{
darwin_adjust_aggregate_sizes (cif->rtype);
for (i = 0; i < cif->nargs; i++)
darwin_adjust_aggregate_sizes (cif->arg_types[i]);
}
/* Space for the frame pointer, callee's LR, CR, etc, and for
the asm's temp regs. */
bytes = (6 + ASM_NEEDS_REGISTERS) * sizeof(long);
/* Return value handling. The rules are as follows:
- 32-bit (or less) integer values are returned in gpr3;
- Structures of size <= 4 bytes also returned in gpr3;
- 64-bit integer values and structures between 5 and 8 bytes are returned
in gpr3 and gpr4;
- Single/double FP values are returned in fpr1;
- Long double FP (if not equivalent to double) values are returned in
fpr1 and fpr2;
- Larger structures values are allocated space and a pointer is passed
as the first argument. */
switch (cif->rtype->type)
{
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
flags |= FLAG_RETURNS_128BITS;
flags |= FLAG_RETURNS_FP;
break;
#endif
case FFI_TYPE_DOUBLE:
flags |= FLAG_RETURNS_64BITS;
/* Fall through. */
case FFI_TYPE_FLOAT:
flags |= FLAG_RETURNS_FP;
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
flags |= FLAG_RETURNS_64BITS;
break;
case FFI_TYPE_STRUCT:
flags |= FLAG_RETVAL_REFERENCE;
flags |= FLAG_RETURNS_NOTHING;
intarg_count++;
break;
case FFI_TYPE_VOID:
flags |= FLAG_RETURNS_NOTHING;
break;
default:
/* Returns 32-bit integer, or similar. Nothing to do here. */
break;
}
/* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
goes on the stack. Structures 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:
fparg_count++;
/* If this FP arg is going on the stack, it must be
8-byte-aligned. */
if (fparg_count > NUM_FPR_ARG_REGISTERS
&& intarg_count%2 != 0)
intarg_count++;
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
fparg_count += 2;
/* If this FP arg is going on the stack, it must be
8-byte-aligned. */
if (fparg_count > NUM_FPR_ARG_REGISTERS
&& intarg_count%2 != 0)
intarg_count++;
intarg_count +=2;
break;
#endif
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 (intarg_count == NUM_GPR_ARG_REGISTERS-1
|| (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0))
intarg_count++;
intarg_count += 2;
break;
case FFI_TYPE_STRUCT:
size_al = (*ptr)->size;
/* If the first member of the struct is a double, then align
the struct to double-word.
Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */
if ((*ptr)->elements[0]->type == 3)
size_al = ALIGN((*ptr)->size, 8);
intarg_count += (size_al + 3) / 4;
break;
default:
/* Everything else is passed as a 4-byte word in a GPR, either
the object itself or a pointer to it. */
intarg_count++;
break;
}
}
if (fparg_count != 0)
flags |= FLAG_FP_ARGUMENTS;
/* Space for the FPR registers, if needed. */
if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
/* Stack space. */
if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS)
bytes += (intarg_count + 2 * fparg_count) * sizeof(long);
else
bytes += NUM_GPR_ARG_REGISTERS * sizeof(long);
/* The stack space allocated needs to be a multiple of 16 bytes. */
bytes = (bytes + 15) & ~0xF;
cif->flags = flags;
cif->bytes = bytes;
return FFI_OK;
}
extern void ffi_call_AIX(extended_cif *, unsigned, unsigned, unsigned *,
void (*fn)(), void (*fn2)());
extern void ffi_call_DARWIN(extended_cif *, unsigned, unsigned, unsigned *,
void (*fn)(), void (*fn2)());
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_AIX:
ffi_call_AIX(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn,
ffi_prep_args);
break;
case FFI_DARWIN:
ffi_call_DARWIN(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn,
ffi_prep_args);
break;
default:
FFI_ASSERT(0);
break;
}
}
static void flush_icache(char *);
static void flush_range(char *, int);
/* The layout of a function descriptor. A C function pointer really
points to one of these. */
typedef struct aix_fd_struct {
void *code_pointer;
void *toc;
} aix_fd;
/* here I'd like to add the stack frame layout we use in darwin_closure.S
and aix_clsoure.S
SP previous -> +---------------------------------------+ <--- child frame
| back chain to caller 4 |
+---------------------------------------+ 4
| saved CR 4 |
+---------------------------------------+ 8
| saved LR 4 |
+---------------------------------------+ 12
| reserved for compilers 4 |
+---------------------------------------+ 16
| reserved for binders 4 |
+---------------------------------------+ 20
| saved TOC pointer 4 |
+---------------------------------------+ 24
| always reserved 8*4=32 (previous GPRs)|
| according to the linkage convention |
| from AIX |
+---------------------------------------+ 56
| our FPR area 13*8=104 |
| f1 |
| . |
| f13 |
+---------------------------------------+ 160
| result area 8 |
+---------------------------------------+ 168
| alignement to the next multiple of 16 |
SP current --> +---------------------------------------+ 176 <- parent frame
| back chain to caller 4 |
+---------------------------------------+ 180
| saved CR 4 |
+---------------------------------------+ 184
| saved LR 4 |
+---------------------------------------+ 188
| reserved for compilers 4 |
+---------------------------------------+ 192
| reserved for binders 4 |
+---------------------------------------+ 196
| saved TOC pointer 4 |
+---------------------------------------+ 200
| always reserved 8*4=32 we store our |
| GPRs here |
| r3 |
| . |
| r10 |
+---------------------------------------+ 232
| overflow part |
+---------------------------------------+ xxx
| ???? |
+---------------------------------------+ xxx
*/
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
unsigned int *tramp;
struct ffi_aix_trampoline_struct *tramp_aix;
aix_fd *fd;
switch (cif->abi)
{
case FFI_DARWIN:
FFI_ASSERT (cif->abi == FFI_DARWIN);
tramp = (unsigned int *) &closure->tramp[0];
tramp[0] = 0x7c0802a6; /* mflr r0 */
tramp[1] = 0x429f000d; /* bcl- 20,4*cr7+so,0x10 */
tramp[4] = 0x7d6802a6; /* mflr r11 */
tramp[5] = 0x818b0000; /* lwz r12,0(r11) function address */
tramp[6] = 0x7c0803a6; /* mtlr r0 */
tramp[7] = 0x7d8903a6; /* mtctr r12 */
tramp[8] = 0x816b0004; /* lwz r11,4(r11) static chain */
tramp[9] = 0x4e800420; /* bctr */
tramp[2] = (unsigned long) ffi_closure_ASM; /* function */
tramp[3] = (unsigned long) closure; /* context */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* Flush the icache. Only necessary on Darwin. */
flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
break;
case FFI_AIX:
tramp_aix = (struct ffi_aix_trampoline_struct *) (closure->tramp);
fd = (aix_fd *)(void *)ffi_closure_ASM;
FFI_ASSERT (cif->abi == FFI_AIX);
tramp_aix->code_pointer = fd->code_pointer;
tramp_aix->toc = fd->toc;
tramp_aix->static_chain = closure;
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
default:
FFI_ASSERT(0);
break;
}
return FFI_OK;
}
static void
flush_icache(char *addr)
{
#ifndef _AIX
__asm__ volatile (
"dcbf 0,%0\n"
"\tsync\n"
"\ticbi 0,%0\n"
"\tsync\n"
"\tisync"
: : "r"(addr) : "memory");
#endif
}
static void
flush_range(char * addr1, int size)
{
#define MIN_LINE_SIZE 32
int i;
for (i = 0; i < size; i += MIN_LINE_SIZE)
flush_icache(addr1+i);
flush_icache(addr1+size-1);
}
typedef union
{
float f;
double d;
} ffi_dblfl;
int ffi_closure_helper_DARWIN (ffi_closure*, void*,
unsigned long*, ffi_dblfl*);
/* Basically the trampoline invokes ffi_closure_ASM, 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_ASM invokes the
following helper function to do most of the work. */
int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue,
unsigned long * pgr, ffi_dblfl * pfr)
{
/* 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_ASM
pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM. */
typedef double ldbits[2];
union ldu
{
ldbits lb;
long double ld;
};
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;
unsigned size_al;
union ldu temp_ld;
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 = (void *) *pgr;
pgr++;
ng++;
}
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:
avalue[i] = (char *) pgr + 3;
ng++;
pgr++;
break;
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
avalue[i] = (char *) pgr + 2;
ng++;
pgr++;
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER:
avalue[i] = pgr;
ng++;
pgr++;
break;
case FFI_TYPE_STRUCT:
/* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
SI 4 bytes) are aligned as if they were those modes. */
size_al = arg_types[i]->size;
/* If the first member of the struct is a double, then align
the struct to double-word.
Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */
if (arg_types[i]->elements[0]->type == 3)
size_al = ALIGN(arg_types[i]->size, 8);
if (size_al < 3 && cif->abi == FFI_DARWIN)
avalue[i] = (void*) pgr + 4 - size_al;
else
avalue[i] = (void*) pgr;
ng += (size_al + 3) / 4;
pgr += (size_al + 3) / 4;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
/* Long long ints are passed in two gpr's. */
avalue[i] = pgr;
ng += 2;
pgr += 2;
break;
case FFI_TYPE_FLOAT:
/* A float value consumes a GPR.
There are 13 64bit floating point registers. */
if (nf < NUM_FPR_ARG_REGISTERS)
{
temp = pfr->d;
pfr->f = (float)temp;
avalue[i] = pfr;
pfr++;
}
else
{
avalue[i] = pgr;
}
nf++;
ng++;
pgr++;
break;
case FFI_TYPE_DOUBLE:
/* A double value consumes two GPRs.
There are 13 64bit floating point registers. */
if (nf < NUM_FPR_ARG_REGISTERS)
{
avalue[i] = pfr;
pfr++;
}
else
{
avalue[i] = pgr;
}
nf++;
ng += 2;
pgr += 2;
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
/* A long double value consumes four GPRs and two FPRs.
There are 13 64bit floating point registers. */
if (nf < NUM_FPR_ARG_REGISTERS - 1)
{
avalue[i] = pfr;
pfr += 2;
}
/* Here we have the situation where one part of the long double
is stored in fpr13 and the other part is already on the stack.
We use a union to pass the long double to avalue[i]. */
else if (nf == NUM_FPR_ARG_REGISTERS - 1)
{
memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits));
memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits));
avalue[i] = &temp_ld.ld;
}
else
{
avalue[i] = pgr;
}
nf += 2;
ng += 4;
pgr += 4;
break;
#endif
default:
FFI_ASSERT(0);
}
i++;
}
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_ASM to perform return type promotions. */
return cif->rtype->type;
}

View File

@@ -0,0 +1,105 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for PowerPC.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- System specific configurations ----------------------------------- */
#if defined (POWERPC) && defined (__powerpc64__)
#define POWERPC64
#endif
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
#ifdef POWERPC
FFI_SYSV,
FFI_GCC_SYSV,
FFI_LINUX64,
FFI_LINUX,
# ifdef POWERPC64
FFI_DEFAULT_ABI = FFI_LINUX64,
# else
# if __LDBL_MANT_DIG__ == 106
FFI_DEFAULT_ABI = FFI_LINUX,
# else
FFI_DEFAULT_ABI = FFI_GCC_SYSV,
# endif
# endif
#endif
#ifdef POWERPC_AIX
FFI_AIX,
FFI_DARWIN,
FFI_DEFAULT_ABI = FFI_AIX,
#endif
#ifdef POWERPC_DARWIN
FFI_AIX,
FFI_DARWIN,
FFI_DEFAULT_ABI = FFI_DARWIN,
#endif
#ifdef POWERPC_FREEBSD
FFI_SYSV,
FFI_GCC_SYSV,
FFI_LINUX64,
FFI_DEFAULT_ABI = FFI_SYSV,
#endif
FFI_LAST_ABI
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
/* Needed for FFI_SYSV small structure returns. */
#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST)
#if defined(POWERPC64) || defined(POWERPC_AIX)
#define FFI_TRAMPOLINE_SIZE 24
#else /* POWERPC || POWERPC_AIX */
#define FFI_TRAMPOLINE_SIZE 40
#endif
#ifndef LIBFFI_ASM
#if defined(POWERPC_DARWIN) || defined(POWERPC_AIX)
struct ffi_aix_trampoline_struct {
void * code_pointer; /* Pointer to ffi_closure_ASM */
void * toc; /* TOC */
void * static_chain; /* Pointer to closure */
};
#endif
#endif
#endif

View File

@@ -0,0 +1,177 @@
/* -----------------------------------------------------------------------
sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
PowerPC64 Assembly glue.
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.
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#ifdef __powerpc64__
.hidden ffi_call_LINUX64, .ffi_call_LINUX64
.globl ffi_call_LINUX64, .ffi_call_LINUX64
.section ".opd","aw"
.align 3
ffi_call_LINUX64:
.quad .ffi_call_LINUX64,.TOC.@tocbase,0
.size ffi_call_LINUX64,24
.type .ffi_call_LINUX64,@function
.text
.ffi_call_LINUX64:
.LFB1:
mflr %r0
std %r28, -32(%r1)
std %r29, -24(%r1)
std %r30, -16(%r1)
std %r31, -8(%r1)
std %r0, 16(%r1)
mr %r28, %r1 /* our AP. */
stdux %r1, %r1, %r4
.LCFI0:
mr %r31, %r5 /* flags, */
mr %r30, %r6 /* rvalue, */
mr %r29, %r7 /* function address. */
std %r2, 40(%r1)
/* Call ffi_prep_args64. */
mr %r4, %r1
bl .ffi_prep_args64
ld %r0, 0(%r29)
ld %r2, 8(%r29)
ld %r11, 16(%r29)
/* Now do the call. */
/* Set up cr1 with bits 4-7 of the flags. */
mtcrf 0x40, %r31
/* Get the address to call into CTR. */
mtctr %r0
/* Load all those argument registers. */
ld %r3, -32-(8*8)(%r28)
ld %r4, -32-(7*8)(%r28)
ld %r5, -32-(6*8)(%r28)
ld %r6, -32-(5*8)(%r28)
bf- 5, 1f
ld %r7, -32-(4*8)(%r28)
ld %r8, -32-(3*8)(%r28)
ld %r9, -32-(2*8)(%r28)
ld %r10, -32-(1*8)(%r28)
1:
/* Load all the FP registers. */
bf- 6, 2f
lfd %f1, -32-(21*8)(%r28)
lfd %f2, -32-(20*8)(%r28)
lfd %f3, -32-(19*8)(%r28)
lfd %f4, -32-(18*8)(%r28)
lfd %f5, -32-(17*8)(%r28)
lfd %f6, -32-(16*8)(%r28)
lfd %f7, -32-(15*8)(%r28)
lfd %f8, -32-(14*8)(%r28)
lfd %f9, -32-(13*8)(%r28)
lfd %f10, -32-(12*8)(%r28)
lfd %f11, -32-(11*8)(%r28)
lfd %f12, -32-(10*8)(%r28)
lfd %f13, -32-(9*8)(%r28)
2:
/* Make the call. */
bctrl
/* Now, deal with the return value. */
mtcrf 0x01, %r31
bt- 30, .Ldone_return_value
bt- 29, .Lfp_return_value
std %r3, 0(%r30)
/* Fall through... */
.Ldone_return_value:
/* Restore the registers we used and return. */
ld %r2, 40(%r1)
mr %r1, %r28
ld %r0, 16(%r28)
ld %r28, -32(%r1)
mtlr %r0
ld %r29, -24(%r1)
ld %r30, -16(%r1)
ld %r31, -8(%r1)
blr
.Lfp_return_value:
bf 28, .Lfloat_return_value
stfd %f1, 0(%r30)
bf 27, .Ldone_return_value
stfd %f2, 8(%r30)
b .Ldone_return_value
.Lfloat_return_value:
stfs %f1, 0(%r30)
b .Ldone_return_value
.LFE1:
.long 0
.byte 0,12,0,1,128,4,0,0
.size .ffi_call_LINUX64,.-.ffi_call_LINUX64
.section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
.LSCIE1:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.uleb128 0x1 # CIE Code Alignment Factor
.sleb128 -8 # CIE Data Alignment Factor
.byte 0x41 # CIE RA Column
.uleb128 0x1 # Augmentation size
.byte 0x14 # FDE Encoding (pcrel udata8)
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1
.uleb128 0x0
.align 3
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 # FDE Length
.LASFDE1:
.4byte .LASFDE1-.Lframe1 # FDE CIE offset
.8byte .LFB1-. # FDE initial location
.8byte .LFE1-.LFB1 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x2 # DW_CFA_advance_loc1
.byte .LCFI0-.LFB1
.byte 0xd # DW_CFA_def_cfa_register
.uleb128 0x1c
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x41
.sleb128 -2
.byte 0x9f # DW_CFA_offset, column 0x1f
.uleb128 0x1
.byte 0x9e # DW_CFA_offset, column 0x1e
.uleb128 0x2
.byte 0x9d # DW_CFA_offset, column 0x1d
.uleb128 0x3
.byte 0x9c # DW_CFA_offset, column 0x1c
.uleb128 0x4
.align 3
.LEFDE1:
#endif

View File

@@ -0,0 +1,206 @@
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.file "linux64_closure.S"
#ifdef __powerpc64__
FFI_HIDDEN (ffi_closure_LINUX64)
FFI_HIDDEN (.ffi_closure_LINUX64)
.globl ffi_closure_LINUX64, .ffi_closure_LINUX64
.section ".opd","aw"
.align 3
ffi_closure_LINUX64:
.quad .ffi_closure_LINUX64,.TOC.@tocbase,0
.size ffi_closure_LINUX64,24
.type .ffi_closure_LINUX64,@function
.text
.ffi_closure_LINUX64:
.LFB1:
# save general regs into parm save area
std %r3, 48(%r1)
std %r4, 56(%r1)
std %r5, 64(%r1)
std %r6, 72(%r1)
mflr %r0
std %r7, 80(%r1)
std %r8, 88(%r1)
std %r9, 96(%r1)
std %r10, 104(%r1)
std %r0, 16(%r1)
# mandatory 48 bytes special reg save area + 64 bytes parm save area
# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
stdu %r1, -240(%r1)
.LCFI0:
# next save fpr 1 to fpr 13
stfd %f1, 128+(0*8)(%r1)
stfd %f2, 128+(1*8)(%r1)
stfd %f3, 128+(2*8)(%r1)
stfd %f4, 128+(3*8)(%r1)
stfd %f5, 128+(4*8)(%r1)
stfd %f6, 128+(5*8)(%r1)
stfd %f7, 128+(6*8)(%r1)
stfd %f8, 128+(7*8)(%r1)
stfd %f9, 128+(8*8)(%r1)
stfd %f10, 128+(9*8)(%r1)
stfd %f11, 128+(10*8)(%r1)
stfd %f12, 128+(11*8)(%r1)
stfd %f13, 128+(12*8)(%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 parameter save area
# in the previous frame
addi %r5, %r1, 240 + 48
# now load up the pointer to the saved fpr registers */
addi %r6, %r1, 128
# make the call
bl .ffi_closure_helper_LINUX64
.Lret:
# 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
mflr %r4 # move address of .Lret to r4
sldi %r3, %r3, 4 # now multiply return type by 16
addi %r4, %r4, .Lret_type0 - .Lret
ld %r0, 240+16(%r1)
add %r3, %r3, %r4 # add contents of table to table address
mtctr %r3
bctr # jump to it
# Each of the ret_typeX code fragments has to be exactly 16 bytes long
# (4 instructions). For cache effectiveness we align to a 16 byte boundary
# first.
.align 4
.Lret_type0:
# case FFI_TYPE_VOID
mtlr %r0
addi %r1, %r1, 240
blr
nop
# case FFI_TYPE_INT
lwa %r3, 112+4(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_FLOAT
lfs %f1, 112+0(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_DOUBLE
lfd %f1, 112+0(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_LONGDOUBLE
lfd %f1, 112+0(%r1)
mtlr %r0
lfd %f2, 112+8(%r1)
b .Lfinish
# case FFI_TYPE_UINT8
lbz %r3, 112+7(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_SINT8
lbz %r3, 112+7(%r1)
extsb %r3,%r3
mtlr %r0
b .Lfinish
# case FFI_TYPE_UINT16
lhz %r3, 112+6(%r1)
mtlr %r0
.Lfinish:
addi %r1, %r1, 240
blr
# case FFI_TYPE_SINT16
lha %r3, 112+6(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_UINT32
lwz %r3, 112+4(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_SINT32
lwa %r3, 112+4(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_UINT64
ld %r3, 112+0(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_SINT64
ld %r3, 112+0(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# case FFI_TYPE_STRUCT
mtlr %r0
addi %r1, %r1, 240
blr
nop
# case FFI_TYPE_POINTER
ld %r3, 112+0(%r1)
mtlr %r0
addi %r1, %r1, 240
blr
# esac
.LFE1:
.long 0
.byte 0,12,0,1,128,0,0,0
.size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
.section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
.LSCIE1:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.uleb128 0x1 # CIE Code Alignment Factor
.sleb128 -8 # CIE Data Alignment Factor
.byte 0x41 # CIE RA Column
.uleb128 0x1 # Augmentation size
.byte 0x14 # FDE Encoding (pcrel udata8)
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1
.uleb128 0x0
.align 3
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 # FDE Length
.LASFDE1:
.4byte .LASFDE1-.Lframe1 # FDE CIE offset
.8byte .LFB1-. # FDE initial location
.8byte .LFE1-.LFB1 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x2 # DW_CFA_advance_loc1
.byte .LCFI0-.LFB1
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 240
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x41
.sleb128 -2
.align 3
.LEFDE1:
#endif

View File

@@ -0,0 +1,283 @@
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#include <powerpc/asm.h>
.file "ppc_closure.S"
#ifndef __powerpc64__
ENTRY(ffi_closure_SYSV)
.LFB1:
stwu %r1,-144(%r1)
.LCFI0:
mflr %r0
.LCFI1:
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 ffi_closure_helper_SYSV@local
.Lret:
# 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
mflr %r4 # move address of .Lret to r4
slwi %r3,%r3,4 # now multiply return type by 16
addi %r4, %r4, .Lret_type0 - .Lret
lwz %r0,148(%r1)
add %r3,%r3,%r4 # add contents of table to table address
mtctr %r3
bctr # jump to it
.LFE1:
# Each of the ret_typeX code fragments has to be exactly 16 bytes long
# (4 instructions). For cache effectiveness we align to a 16 byte boundary
# first.
.align 4
# case FFI_TYPE_VOID
.Lret_type0:
mtlr %r0
addi %r1,%r1,144
blr
nop
# case FFI_TYPE_INT
lwz %r3,112+0(%r1)
mtlr %r0
.Lfinish:
addi %r1,%r1,144
blr
# case FFI_TYPE_FLOAT
lfs %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_DOUBLE
lfd %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_LONGDOUBLE
lfd %f1,112+0(%r1)
lfd %f2,112+8(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_UINT8
lbz %r3,112+3(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT8
lbz %r3,112+3(%r1)
extsb %r3,%r3
mtlr %r0
b .Lfinish
# case FFI_TYPE_UINT16
lhz %r3,112+2(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT16
lha %r3,112+2(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_UINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_UINT64
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_SINT64
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_STRUCT
mtlr %r0
addi %r1,%r1,144
blr
nop
# case FFI_TYPE_POINTER
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# The return types below are only used when the ABI type is FFI_SYSV.
# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
lbz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
lhz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
lwz %r3,112+0(%r1)
srwi %r3,%r3,8
mtlr %r0
b .Lfinish
# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,24
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,16
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,8
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
.Lstruct567:
subfic %r6,%r5,32
srw %r4,%r4,%r5
slw %r6,%r3,%r6
srw %r3,%r3,%r5
or %r4,%r6,%r4
mtlr %r0
addi %r1,%r1,144
blr
END(ffi_closure_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
.LSCIE1:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
#if defined _RELOCATABLE || defined __PIC__
.ascii "zR\0" # CIE Augmentation
#else
.ascii "\0" # CIE Augmentation
#endif
.uleb128 0x1 # CIE Code Alignment Factor
.sleb128 -4 # CIE Data Alignment Factor
.byte 0x41 # CIE RA Column
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x1 # Augmentation size
.byte 0x1b # FDE Encoding (pcrel sdata4)
#endif
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1
.uleb128 0x0
.align 2
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 # FDE Length
.LASFDE1:
.4byte .LASFDE1-.Lframe1 # FDE CIE offset
#if defined _RELOCATABLE || defined __PIC__
.4byte .LFB1-. # FDE initial location
#else
.4byte .LFB1 # FDE initial location
#endif
.4byte .LFE1-.LFB1 # FDE address range
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x0 # Augmentation size
#endif
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI0-.LFB1
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 144
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI1-.LCFI0
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x41
.sleb128 -1
.align 2
.LEFDE1:
#endif

219
libffi/src/powerpc/sysv.S Normal file
View File

@@ -0,0 +1,219 @@
/* -----------------------------------------------------------------------
sysv.h - Copyright (c) 1998 Geoffrey Keating
PowerPC Assembly glue.
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.
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#include <powerpc/asm.h>
#ifndef __powerpc64__
.globl ffi_prep_args_SYSV
ENTRY(ffi_call_SYSV)
.LFB1:
/* Save the old stack pointer as AP. */
mr %r8,%r1
.LCFI0:
/* Allocate the stack space we need. */
stwux %r1,%r1,%r4
/* Save registers we use. */
mflr %r9
stw %r28,-16(%r8)
.LCFI1:
stw %r29,-12(%r8)
.LCFI2:
stw %r30, -8(%r8)
.LCFI3:
stw %r31, -4(%r8)
.LCFI4:
stw %r9, 4(%r8)
.LCFI5:
/* Save arguments over call... */
mr %r31,%r5 /* flags, */
mr %r30,%r6 /* rvalue, */
mr %r29,%r7 /* function address, */
mr %r28,%r8 /* our AP. */
.LCFI6:
/* Call ffi_prep_args_SYSV. */
mr %r4,%r1
bl ffi_prep_args_SYSV@local
/* Now do the call. */
/* Set up cr1 with bits 4-7 of the flags. */
mtcrf 0x40,%r31
/* Get the address to call into CTR. */
mtctr %r29
/* Load all those argument registers. */
lwz %r3,-16-(8*4)(%r28)
lwz %r4,-16-(7*4)(%r28)
lwz %r5,-16-(6*4)(%r28)
lwz %r6,-16-(5*4)(%r28)
bf- 5,1f
nop
lwz %r7,-16-(4*4)(%r28)
lwz %r8,-16-(3*4)(%r28)
lwz %r9,-16-(2*4)(%r28)
lwz %r10,-16-(1*4)(%r28)
nop
1:
/* Load all the FP registers. */
bf- 6,2f
lfd %f1,-16-(8*4)-(8*8)(%r28)
lfd %f2,-16-(8*4)-(7*8)(%r28)
lfd %f3,-16-(8*4)-(6*8)(%r28)
lfd %f4,-16-(8*4)-(5*8)(%r28)
nop
lfd %f5,-16-(8*4)-(4*8)(%r28)
lfd %f6,-16-(8*4)-(3*8)(%r28)
lfd %f7,-16-(8*4)-(2*8)(%r28)
lfd %f8,-16-(8*4)-(1*8)(%r28)
2:
/* Make the call. */
bctrl
/* Now, deal with the return value. */
mtcrf 0x01,%r31
bt- 31,L(small_struct_return_value)
bt- 30,L(done_return_value)
bt- 29,L(fp_return_value)
stw %r3,0(%r30)
bf+ 28,L(done_return_value)
stw %r4,4(%r30)
/* Fall through... */
L(done_return_value):
/* Restore the registers we used and return. */
lwz %r9, 4(%r28)
lwz %r31, -4(%r28)
mtlr %r9
lwz %r30, -8(%r28)
lwz %r29,-12(%r28)
lwz %r28,-16(%r28)
lwz %r1,0(%r1)
blr
L(fp_return_value):
bf 28,L(float_return_value)
stfd %f1,0(%r30)
bf 27,L(done_return_value)
stfd %f2,8(%r30)
b L(done_return_value)
L(float_return_value):
stfs %f1,0(%r30)
b L(done_return_value)
L(small_struct_return_value):
mtcrf 0x10,%r31 /* cr3 */
bt- 15,L(smst_one_register)
mtcrf 0x08,%r31 /* cr4 */
bt- 16,L(smst_two_register)
b L(done_return_value)
L(smst_one_register):
rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */
slw %r3,%r3,%r5
stw %r3,0(%r30)
b L(done_return_value)
L(smst_two_register):
rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */
cmpwi %r5,0
subfic %r9,%r5,32
slw %r29,%r3,%r5
srw %r9,%r4,%r9
beq- L(smst_8byte)
or %r3,%r9,%r29
slw %r4,%r4,%r5
L(smst_8byte):
stw %r3,0(%r30)
stw %r4,4(%r30)
b L(done_return_value)
.LFE1:
END(ffi_call_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
.LSCIE1:
.4byte 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#if defined _RELOCATABLE || defined __PIC__
.ascii "zR\0" /* CIE Augmentation */
#else
.ascii "\0" /* CIE Augmentation */
#endif
.uleb128 0x1 /* CIE Code Alignment Factor */
.sleb128 -4 /* CIE Data Alignment Factor */
.byte 0x41 /* CIE RA Column */
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x1 /* Augmentation size */
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
#endif
.byte 0xc /* DW_CFA_def_cfa */
.uleb128 0x1
.uleb128 0x0
.align 2
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.4byte .LASFDE1-.Lframe1 /* FDE CIE offset */
#if defined _RELOCATABLE || defined __PIC__
.4byte .LFB1-. /* FDE initial location */
#else
.4byte .LFB1 /* FDE initial location */
#endif
.4byte .LFE1-.LFB1 /* FDE address range */
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x0 /* Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI0-.LFB1
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0x08
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI5-.LCFI0
.byte 0x11 /* DW_CFA_offset_extended_sf */
.uleb128 0x41
.sleb128 -1
.byte 0x9f /* DW_CFA_offset, column 0x1f */
.uleb128 0x1
.byte 0x9e /* DW_CFA_offset, column 0x1e */
.uleb128 0x2
.byte 0x9d /* DW_CFA_offset, column 0x1d */
.uleb128 0x3
.byte 0x9c /* DW_CFA_offset, column 0x1c */
.uleb128 0x4
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI6-.LCFI5
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0x1c
.align 2
.LEFDE1:
#endif

160
libffi/src/prep_cif.c Normal file
View File

@@ -0,0 +1,160 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc.
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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* Round up to FFI_SIZEOF_ARG. */
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
/* Perform machine independent initialization of aggregate type
specifications. */
static ffi_status initialize_aggregate(ffi_type *arg)
{
ffi_type **ptr;
FFI_ASSERT(arg != NULL);
FFI_ASSERT(arg->elements != NULL);
FFI_ASSERT(arg->size == 0);
FFI_ASSERT(arg->alignment == 0);
ptr = &(arg->elements[0]);
while ((*ptr) != NULL)
{
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type */
FFI_ASSERT_VALID_TYPE(*ptr);
arg->size = ALIGN(arg->size, (*ptr)->alignment);
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
arg->alignment : (*ptr)->alignment;
ptr++;
}
/* Structure size includes tail padding. This is important for
structures that fit in one register on ABIs like the PowerPC64
Linux ABI that right justify small structs in a register.
It's also needed for nested structure layout, for example
struct A { long a; char b; }; struct B { struct A x; char y; };
should find y at an offset of 2*sizeof(long) and result in a
total size of 3*sizeof(long). */
arg->size = ALIGN (arg->size, arg->alignment);
if (arg->size == 0)
return FFI_BAD_TYPEDEF;
else
return FFI_OK;
}
#ifndef __CRIS__
/* The CRIS ABI specifies structure elements to have byte
alignment only, so it completely overrides this functions,
which assumes "natural" alignment and padding. */
/* Perform machine independent ffi_cif preparation, then call
machine dependent routine. */
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
ffi_type *rtype, ffi_type **atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT(cif != NULL);
FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->rtype = rtype;
cif->flags = 0;
/* Initialize the return type if necessary */
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the return type */
FFI_ASSERT_VALID_TYPE(cif->rtype);
/* x86-64 and s390 stack space allocation is handled in prep_machdep. */
#if !defined M68K && !defined __x86_64__ && !defined S390 && !defined PA
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
#endif
#ifdef X86_DARWIN
&& (cif->rtype->size > 8)
#endif
)
bytes = STACK_ARG_SIZE(sizeof(void*));
#endif
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
/* Initialize any uninitialized aggregate type definitions */
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type, do this
check after the initialization. */
FFI_ASSERT_VALID_TYPE(*ptr);
#if !defined __x86_64__ && !defined S390 && !defined PA
#ifdef SPARC
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
{
/* Add any padding if necessary */
if (((*ptr)->alignment - 1) & bytes)
bytes = ALIGN(bytes, (*ptr)->alignment);
bytes += STACK_ARG_SIZE((*ptr)->size);
}
#endif
}
cif->bytes = bytes;
/* Perform machine dependent cif processing */
return ffi_prep_cif_machdep(cif);
}
#endif /* not __CRIS__ */

239
libffi/src/raw_api.c Normal file
View File

@@ -0,0 +1,239 @@
/* -----------------------------------------------------------------------
raw_api.c - Copyright (c) 1999 Red Hat, Inc.
Author: Kresten Krab Thorup <krab@gnu.org>
$Id $
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.
----------------------------------------------------------------------- */
/* This file defines generic functions for use with the raw api. */
#include <ffi.h>
#include <ffi_common.h>
#if !FFI_NO_RAW_API
size_t
ffi_raw_size (ffi_cif *cif)
{
size_t result = 0;
int i;
ffi_type **at = cif->arg_types;
for (i = cif->nargs-1; i >= 0; i--, at++)
{
#if !FFI_NO_STRUCTS
if ((*at)->type == FFI_TYPE_STRUCT)
result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
else
#endif
result += ALIGN ((*at)->size, FFI_SIZEOF_ARG);
}
return result;
}
void
ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
{
unsigned i;
ffi_type **tp = cif->arg_types;
#if WORDS_BIGENDIAN
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
switch ((*tp)->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
*args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 1);
break;
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
*args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 2);
break;
#if FFI_SIZEOF_ARG >= 4
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
*args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 4);
break;
#endif
#if !FFI_NO_STRUCTS
case FFI_TYPE_STRUCT:
*args = (raw++)->ptr;
break;
#endif
case FFI_TYPE_POINTER:
*args = (void*) &(raw++)->ptr;
break;
default:
*args = raw;
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
#else /* WORDS_BIGENDIAN */
#if !PDP
/* then assume little endian */
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
#if !FFI_NO_STRUCTS
if ((*tp)->type == FFI_TYPE_STRUCT)
{
*args = (raw++)->ptr;
}
else
#endif
{
*args = (void*) raw;
raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
}
}
#else
#error "pdp endian not supported"
#endif /* ! PDP */
#endif /* WORDS_BIGENDIAN */
}
void
ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
{
unsigned i;
ffi_type **tp = cif->arg_types;
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
switch ((*tp)->type)
{
case FFI_TYPE_UINT8:
(raw++)->uint = *(UINT8*) (*args);
break;
case FFI_TYPE_SINT8:
(raw++)->sint = *(SINT8*) (*args);
break;
case FFI_TYPE_UINT16:
(raw++)->uint = *(UINT16*) (*args);
break;
case FFI_TYPE_SINT16:
(raw++)->sint = *(SINT16*) (*args);
break;
#if FFI_SIZEOF_ARG >= 4
case FFI_TYPE_UINT32:
(raw++)->uint = *(UINT32*) (*args);
break;
case FFI_TYPE_SINT32:
(raw++)->sint = *(SINT32*) (*args);
break;
#endif
#if !FFI_NO_STRUCTS
case FFI_TYPE_STRUCT:
(raw++)->ptr = *args;
break;
#endif
case FFI_TYPE_POINTER:
(raw++)->ptr = **(void***) args;
break;
default:
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
}
#if !FFI_NATIVE_RAW_API
/* This is a generic definition of ffi_raw_call, to be used if the
* native system does not provide a machine-specific implementation.
* Having this, allows code to be written for the raw API, without
* the need for system-specific code to handle input in that format;
* these following couple of functions will handle the translation forth
* and back automatically. */
void ffi_raw_call (ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *raw)
{
void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
ffi_raw_to_ptrarray (cif, raw, avalue);
ffi_call (cif, fn, rvalue, avalue);
}
#if FFI_CLOSURES /* base system provides closures */
static void
ffi_translate_args (ffi_cif *cif, void *rvalue,
void **avalue, void *user_data)
{
ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
ffi_ptrarray_to_raw (cif, avalue, raw);
(*cl->fun) (cif, rvalue, raw, cl->user_data);
}
/* Again, here is the generic version of ffi_prep_raw_closure, which
* will install an intermediate "hub" for translation of arguments from
* the pointer-array format, to the raw format */
ffi_status
ffi_prep_raw_closure (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
{
ffi_status status;
status = ffi_prep_closure ((ffi_closure*) cl,
cif,
&ffi_translate_args,
(void*)cl);
if (status == FFI_OK)
{
cl->fun = fun;
cl->user_data = user_data;
}
return status;
}
#endif /* FFI_CLOSURES */
#endif /* !FFI_NATIVE_RAW_API */
#endif /* !FFI_NO_RAW_API */

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

@@ -0,0 +1,751 @@
/* -----------------------------------------------------------------------
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 */
/* ------- */
/*====================================================================*/
/* Maximum number of GPRs available for argument passing. */
#define MAX_GPRARGS 5
/* Maximum number of FPRs available for argument passing. */
#ifdef __s390x__
#define MAX_FPRARGS 4
#else
#define MAX_FPRARGS 2
#endif
/* Round to multiple of 16. */
#define ROUND_SIZE(size) (((size) + 15) & ~15)
/* If these values change, sysv.S must be adapted! */
#define FFI390_RET_VOID 0
#define FFI390_RET_STRUCT 1
#define FFI390_RET_FLOAT 2
#define FFI390_RET_DOUBLE 3
#define FFI390_RET_INT32 4
#define FFI390_RET_INT64 5
/*===================== End of Defines ===============================*/
/*====================================================================*/
/* Prototypes */
/* ---------- */
/*====================================================================*/
static void ffi_prep_args (unsigned char *, extended_cif *);
void
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
__attribute__ ((visibility ("hidden")))
#endif
ffi_closure_helper_SYSV (ffi_closure *, unsigned long *,
unsigned long long *, unsigned long *);
/*====================== End of Prototypes ===========================*/
/*====================================================================*/
/* Externals */
/* --------- */
/*====================================================================*/
extern void ffi_call_SYSV(unsigned,
extended_cif *,
void (*)(unsigned char *, extended_cif *),
unsigned,
void *,
void (*fn)());
extern void ffi_closure_SYSV(void);
/*====================== End of Externals ============================*/
/*====================================================================*/
/* */
/* Name - ffi_check_struct_type. */
/* */
/* Function - Determine if a structure can be passed within a */
/* general purpose or floating point register. */
/* */
/*====================================================================*/
static int
ffi_check_struct_type (ffi_type *arg)
{
size_t size = arg->size;
/* If the struct has just one element, look at that element
to find out whether to consider the struct as floating point. */
while (arg->type == FFI_TYPE_STRUCT
&& arg->elements[0] && !arg->elements[1])
arg = arg->elements[0];
/* Structs of size 1, 2, 4, and 8 are passed in registers,
just like the corresponding int/float types. */
switch (size)
{
case 1:
return FFI_TYPE_UINT8;
case 2:
return FFI_TYPE_UINT16;
case 4:
if (arg->type == FFI_TYPE_FLOAT)
return FFI_TYPE_FLOAT;
else
return FFI_TYPE_UINT32;
case 8:
if (arg->type == FFI_TYPE_DOUBLE)
return FFI_TYPE_DOUBLE;
else
return FFI_TYPE_UINT64;
default:
break;
}
/* Other structs are passed via a pointer to the data. */
return FFI_TYPE_POINTER;
}
/*======================== 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. */
/* */
/*====================================================================*/
static void
ffi_prep_args (unsigned char *stack, extended_cif *ecif)
{
/* The stack space will be filled with those areas:
FPR argument register save area (highest addresses)
GPR argument register save area
temporary struct copies
overflow argument area (lowest addresses)
We set up the following pointers:
p_fpr: bottom of the FPR area (growing upwards)
p_gpr: bottom of the GPR area (growing upwards)
p_ov: bottom of the overflow area (growing upwards)
p_struct: top of the struct copy area (growing downwards)
All areas are kept aligned to twice the word size. */
int gpr_off = ecif->cif->bytes;
int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
unsigned char *p_struct = (unsigned char *)p_gpr;
unsigned long *p_ov = (unsigned long *)stack;
int n_fpr = 0;
int n_gpr = 0;
int n_ov = 0;
ffi_type **ptr;
void **p_argv = ecif->avalue;
int i;
/* If we returning a structure then we set the first parameter register
to the address of where we are returning this structure. */
if (ecif->cif->flags == FFI390_RET_STRUCT)
p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
/* Now for the arguments. */
for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
i > 0;
i--, ptr++, p_argv++)
{
void *arg = *p_argv;
int type = (*ptr)->type;
/* Check how a structure type is passed. */
if (type == FFI_TYPE_STRUCT)
{
type = ffi_check_struct_type (*ptr);
/* If we pass the struct via pointer, copy the data. */
if (type == FFI_TYPE_POINTER)
{
p_struct -= ROUND_SIZE ((*ptr)->size);
memcpy (p_struct, (char *)arg, (*ptr)->size);
arg = &p_struct;
}
}
/* Now handle all primitive int/pointer/float data types. */
switch (type)
{
case FFI_TYPE_DOUBLE:
if (n_fpr < MAX_FPRARGS)
p_fpr[n_fpr++] = *(unsigned long long *) arg;
else
#ifdef __s390x__
p_ov[n_ov++] = *(unsigned long *) arg;
#else
p_ov[n_ov++] = ((unsigned long *) arg)[0],
p_ov[n_ov++] = ((unsigned long *) arg)[1];
#endif
break;
case FFI_TYPE_FLOAT:
if (n_fpr < MAX_FPRARGS)
p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
else
p_ov[n_ov++] = *(unsigned int *) arg;
break;
case FFI_TYPE_POINTER:
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
else
p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
#ifdef __s390x__
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = *(unsigned long *) arg;
else
p_ov[n_ov++] = *(unsigned long *) arg;
#else
if (n_gpr == MAX_GPRARGS-1)
n_gpr = MAX_GPRARGS;
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
else
p_ov[n_ov++] = ((unsigned long *) arg)[0],
p_ov[n_ov++] = ((unsigned long *) arg)[1];
#endif
break;
case FFI_TYPE_UINT32:
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = *(unsigned int *) arg;
else
p_ov[n_ov++] = *(unsigned int *) arg;
break;
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = *(signed int *) arg;
else
p_ov[n_ov++] = *(signed int *) arg;
break;
case FFI_TYPE_UINT16:
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = *(unsigned short *) arg;
else
p_ov[n_ov++] = *(unsigned short *) arg;
break;
case FFI_TYPE_SINT16:
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = *(signed short *) arg;
else
p_ov[n_ov++] = *(signed short *) arg;
break;
case FFI_TYPE_UINT8:
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = *(unsigned char *) arg;
else
p_ov[n_ov++] = *(unsigned char *) arg;
break;
case FFI_TYPE_SINT8:
if (n_gpr < MAX_GPRARGS)
p_gpr[n_gpr++] = *(signed char *) arg;
else
p_ov[n_ov++] = *(signed char *) arg;
break;
default:
FFI_ASSERT (0);
break;
}
}
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_prep_cif_machdep. */
/* */
/* Function - Perform machine dependent CIF processing. */
/* */
/*====================================================================*/
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
size_t struct_size = 0;
int n_gpr = 0;
int n_fpr = 0;
int n_ov = 0;
ffi_type **ptr;
int i;
/* Determine return value handling. */
switch (cif->rtype->type)
{
/* Void is easy. */
case FFI_TYPE_VOID:
cif->flags = FFI390_RET_VOID;
break;
/* Structures are returned via a hidden pointer. */
case FFI_TYPE_STRUCT:
cif->flags = FFI390_RET_STRUCT;
n_gpr++; /* We need one GPR to pass the pointer. */
break;
/* Floating point values are returned in fpr 0. */
case FFI_TYPE_FLOAT:
cif->flags = FFI390_RET_FLOAT;
break;
case FFI_TYPE_DOUBLE:
cif->flags = FFI390_RET_DOUBLE;
break;
/* Integer values are returned in gpr 2 (and gpr 3
for 64-bit values on 31-bit machines). */
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
cif->flags = FFI390_RET_INT64;
break;
case FFI_TYPE_POINTER:
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
/* These are to be extended to word size. */
#ifdef __s390x__
cif->flags = FFI390_RET_INT64;
#else
cif->flags = FFI390_RET_INT32;
#endif
break;
default:
FFI_ASSERT (0);
break;
}
/* Now for the arguments. */
for (ptr = cif->arg_types, i = cif->nargs;
i > 0;
i--, ptr++)
{
int type = (*ptr)->type;
/* Check how a structure type is passed. */
if (type == FFI_TYPE_STRUCT)
{
type = ffi_check_struct_type (*ptr);
/* If we pass the struct via pointer, we must reserve space
to copy its data for proper call-by-value semantics. */
if (type == FFI_TYPE_POINTER)
struct_size += ROUND_SIZE ((*ptr)->size);
}
/* Now handle all primitive int/float data types. */
switch (type)
{
/* The first MAX_FPRARGS floating point arguments
go in FPRs, the rest overflow to the stack. */
case FFI_TYPE_DOUBLE:
if (n_fpr < MAX_FPRARGS)
n_fpr++;
else
n_ov += sizeof (double) / sizeof (long);
break;
case FFI_TYPE_FLOAT:
if (n_fpr < MAX_FPRARGS)
n_fpr++;
else
n_ov++;
break;
/* On 31-bit machines, 64-bit integers are passed in GPR pairs,
if one is still available, or else on the stack. If only one
register is free, skip the register (it won't be used for any
subsequent argument either). */
#ifndef __s390x__
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
if (n_gpr == MAX_GPRARGS-1)
n_gpr = MAX_GPRARGS;
if (n_gpr < MAX_GPRARGS)
n_gpr += 2;
else
n_ov += 2;
break;
#endif
/* Everything else is passed in GPRs (until MAX_GPRARGS
have been used) or overflows to the stack. */
default:
if (n_gpr < MAX_GPRARGS)
n_gpr++;
else
n_ov++;
break;
}
}
/* Total stack space as required for overflow arguments
and temporary structure copies. */
cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
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)
{
int ret_type = cif->flags;
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
ecif.rvalue = rvalue;
/* If we don't have a return value, we need to fake one. */
if (rvalue == NULL)
{
if (ret_type == FFI390_RET_STRUCT)
ecif.rvalue = alloca (cif->rtype->size);
else
ret_type = FFI390_RET_VOID;
}
switch (cif->abi)
{
case FFI_SYSV:
ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
ret_type, ecif.rvalue, fn);
break;
default:
FFI_ASSERT (0);
break;
}
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_closure_helper_SYSV. */
/* */
/* Function - Call a FFI closure target function. */
/* */
/*====================================================================*/
void
ffi_closure_helper_SYSV (ffi_closure *closure,
unsigned long *p_gpr,
unsigned long long *p_fpr,
unsigned long *p_ov)
{
unsigned long long ret_buffer;
void *rvalue = &ret_buffer;
void **avalue;
void **p_arg;
int n_gpr = 0;
int n_fpr = 0;
int n_ov = 0;
ffi_type **ptr;
int i;
/* Allocate buffer for argument list pointers. */
p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
/* If we returning a structure, pass the structure address
directly to the target function. Otherwise, have the target
function store the return value to the GPR save area. */
if (closure->cif->flags == FFI390_RET_STRUCT)
rvalue = (void *) p_gpr[n_gpr++];
/* Now for the arguments. */
for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
i > 0;
i--, p_arg++, ptr++)
{
int deref_struct_pointer = 0;
int type = (*ptr)->type;
/* Check how a structure type is passed. */
if (type == FFI_TYPE_STRUCT)
{
type = ffi_check_struct_type (*ptr);
/* If we pass the struct via pointer, remember to
retrieve the pointer later. */
if (type == FFI_TYPE_POINTER)
deref_struct_pointer = 1;
}
/* Pointers are passed like UINTs of the same size. */
if (type == FFI_TYPE_POINTER)
#ifdef __s390x__
type = FFI_TYPE_UINT64;
#else
type = FFI_TYPE_UINT32;
#endif
/* Now handle all primitive int/float data types. */
switch (type)
{
case FFI_TYPE_DOUBLE:
if (n_fpr < MAX_FPRARGS)
*p_arg = &p_fpr[n_fpr++];
else
*p_arg = &p_ov[n_ov],
n_ov += sizeof (double) / sizeof (long);
break;
case FFI_TYPE_FLOAT:
if (n_fpr < MAX_FPRARGS)
*p_arg = &p_fpr[n_fpr++];
else
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
#ifdef __s390x__
if (n_gpr < MAX_GPRARGS)
*p_arg = &p_gpr[n_gpr++];
else
*p_arg = &p_ov[n_ov++];
#else
if (n_gpr == MAX_GPRARGS-1)
n_gpr = MAX_GPRARGS;
if (n_gpr < MAX_GPRARGS)
*p_arg = &p_gpr[n_gpr], n_gpr += 2;
else
*p_arg = &p_ov[n_ov], n_ov += 2;
#endif
break;
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
if (n_gpr < MAX_GPRARGS)
*p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
else
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
break;
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
if (n_gpr < MAX_GPRARGS)
*p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
else
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
break;
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
if (n_gpr < MAX_GPRARGS)
*p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
else
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
break;
default:
FFI_ASSERT (0);
break;
}
/* If this is a struct passed via pointer, we need to
actually retrieve that pointer. */
if (deref_struct_pointer)
*p_arg = *(void **)*p_arg;
}
/* Call the target function. */
(closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
/* Convert the return value. */
switch (closure->cif->rtype->type)
{
/* Void is easy, and so is struct. */
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
break;
/* Floating point values are returned in fpr 0. */
case FFI_TYPE_FLOAT:
p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
break;
case FFI_TYPE_DOUBLE:
p_fpr[0] = *(unsigned long long *) rvalue;
break;
/* Integer values are returned in gpr 2 (and gpr 3
for 64-bit values on 31-bit machines). */
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
#ifdef __s390x__
p_gpr[0] = *(unsigned long *) rvalue;
#else
p_gpr[0] = ((unsigned long *) rvalue)[0],
p_gpr[1] = ((unsigned long *) rvalue)[1];
#endif
break;
case FFI_TYPE_POINTER:
case FFI_TYPE_UINT32:
case FFI_TYPE_UINT16:
case FFI_TYPE_UINT8:
p_gpr[0] = *(unsigned long *) rvalue;
break;
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
case FFI_TYPE_SINT16:
case FFI_TYPE_SINT8:
p_gpr[0] = *(signed long *) rvalue;
break;
default:
FFI_ASSERT (0);
break;
}
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_prep_closure. */
/* */
/* Function - Prepare a FFI closure. */
/* */
/*====================================================================*/
ffi_status
ffi_prep_closure (ffi_closure *closure,
ffi_cif *cif,
void (*fun) (ffi_cif *, void *, void **, void *),
void *user_data)
{
FFI_ASSERT (cif->abi == FFI_SYSV);
#ifndef __s390x__
*(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
*(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
*(short *)&closure->tramp [4] = 0x1006;
*(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
*(long *)&closure->tramp [8] = (long)closure;
*(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
#else
*(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
*(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
*(short *)&closure->tramp [4] = 0x100e;
*(short *)&closure->tramp [6] = 0x0004;
*(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
*(long *)&closure->tramp[16] = (long)closure;
*(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
#endif
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
/*======================== End of Routine ============================*/

View File

@@ -0,0 +1,59 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for S390.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#if defined (__s390x__)
#define S390X
#endif
/* ---- System specific configurations ----------------------------------- */
#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
#ifdef S390X
#define FFI_TRAMPOLINE_SIZE 32
#else
#define FFI_TRAMPOLINE_SIZE 16
#endif
#define FFI_NATIVE_RAW_API 0
#endif

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

@@ -0,0 +1,429 @@
/* -----------------------------------------------------------------------
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 <fficonfig.h>
#include <ffi.h>
#ifndef __s390x__
.text
# r2: cif->bytes
# r3: &ecif
# r4: ffi_prep_args
# r5: ret_type
# r6: ecif.rvalue
# ov: fn
# This assumes we are using gas.
.globl ffi_call_SYSV
.type ffi_call_SYSV,%function
ffi_call_SYSV:
.LFB1:
stm %r6,%r15,24(%r15) # Save registers
.LCFI0:
basr %r13,0 # Set up base register
.Lbase:
lr %r11,%r15 # Set up frame pointer
.LCFI1:
sr %r15,%r2
ahi %r15,-96-48 # Allocate stack
lr %r8,%r6 # Save ecif.rvalue
sr %r9,%r9
ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
l %r7,96(%r11) # Load function address
st %r11,0(%r15) # Set up back chain
ahi %r11,-48 # Register save area
.LCFI2:
la %r2,96(%r15) # Save area
# r3 already holds &ecif
basr %r14,%r4 # Call ffi_prep_args
lm %r2,%r6,0(%r11) # Load arguments
ld %f0,32(%r11)
ld %f2,40(%r11)
la %r14,0(%r13,%r9) # Set return address
br %r7 # ... and call function
.LretNone: # Return void
l %r4,48+56(%r11)
lm %r6,%r15,48+24(%r11)
br %r4
.LretFloat:
l %r4,48+56(%r11)
ste %f0,0(%r8) # Return float
lm %r6,%r15,48+24(%r11)
br %r4
.LretDouble:
l %r4,48+56(%r11)
std %f0,0(%r8) # Return double
lm %r6,%r15,48+24(%r11)
br %r4
.LretInt32:
l %r4,48+56(%r11)
st %r2,0(%r8) # Return int
lm %r6,%r15,48+24(%r11)
br %r4
.LretInt64:
l %r4,48+56(%r11)
stm %r2,%r3,0(%r8) # Return long long
lm %r6,%r15,48+24(%r11)
br %r4
.Ltable:
.byte .LretNone-.Lbase # FFI390_RET_VOID
.byte .LretNone-.Lbase # FFI390_RET_STRUCT
.byte .LretFloat-.Lbase # FFI390_RET_FLOAT
.byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
.byte .LretInt32-.Lbase # FFI390_RET_INT32
.byte .LretInt64-.Lbase # FFI390_RET_INT64
.LFE1:
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
.globl ffi_closure_SYSV
.type ffi_closure_SYSV,%function
ffi_closure_SYSV:
.LFB2:
stm %r12,%r15,48(%r15) # Save registers
.LCFI10:
basr %r13,0 # Set up base register
.Lcbase:
stm %r2,%r6,8(%r15) # Save arguments
std %f0,64(%r15)
std %f2,72(%r15)
lr %r1,%r15 # Set up stack frame
ahi %r15,-96
.LCFI11:
l %r12,.Lchelper-.Lcbase(%r13) # Get helper function
lr %r2,%r0 # Closure
la %r3,8(%r1) # GPRs
la %r4,64(%r1) # FPRs
la %r5,96(%r1) # Overflow
st %r1,0(%r15) # Set up back chain
bas %r14,0(%r12,%r13) # Call helper
l %r4,96+56(%r15)
ld %f0,96+64(%r15) # Load return registers
lm %r2,%r3,96+8(%r15)
lm %r12,%r15,96+48(%r15)
br %r4
.align 4
.Lchelper:
.long ffi_closure_helper_SYSV-.Lcbase
.LFE2:
.ffi_closure_SYSV_end:
.size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
.section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
.LSCIE1:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.uleb128 0x1 # CIE Code Alignment Factor
.sleb128 -4 # CIE Data Alignment Factor
.byte 0xe # CIE RA Column
.uleb128 0x1 # Augmentation size
.byte 0x1b # FDE Encoding (pcrel sdata4)
.byte 0xc # DW_CFA_def_cfa
.uleb128 0xf
.uleb128 0x60
.align 4
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 # FDE Length
.LASFDE1:
.4byte .LASFDE1-.Lframe1 # FDE CIE offset
.4byte .LFB1-. # FDE initial location
.4byte .LFE1-.LFB1 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI0-.LFB1
.byte 0x8f # DW_CFA_offset, column 0xf
.uleb128 0x9
.byte 0x8e # DW_CFA_offset, column 0xe
.uleb128 0xa
.byte 0x8d # DW_CFA_offset, column 0xd
.uleb128 0xb
.byte 0x8c # DW_CFA_offset, column 0xc
.uleb128 0xc
.byte 0x8b # DW_CFA_offset, column 0xb
.uleb128 0xd
.byte 0x8a # DW_CFA_offset, column 0xa
.uleb128 0xe
.byte 0x89 # DW_CFA_offset, column 0x9
.uleb128 0xf
.byte 0x88 # DW_CFA_offset, column 0x8
.uleb128 0x10
.byte 0x87 # DW_CFA_offset, column 0x7
.uleb128 0x11
.byte 0x86 # DW_CFA_offset, column 0x6
.uleb128 0x12
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI1-.LCFI0
.byte 0xd # DW_CFA_def_cfa_register
.uleb128 0xb
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI2-.LCFI1
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0x90
.align 4
.LEFDE1:
.LSFDE2:
.4byte .LEFDE2-.LASFDE2 # FDE Length
.LASFDE2:
.4byte .LASFDE2-.Lframe1 # FDE CIE offset
.4byte .LFB2-. # FDE initial location
.4byte .LFE2-.LFB2 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI10-.LFB2
.byte 0x8f # DW_CFA_offset, column 0xf
.uleb128 0x9
.byte 0x8e # DW_CFA_offset, column 0xe
.uleb128 0xa
.byte 0x8d # DW_CFA_offset, column 0xd
.uleb128 0xb
.byte 0x8c # DW_CFA_offset, column 0xc
.uleb128 0xc
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI11-.LCFI10
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0xc0
.align 4
.LEFDE2:
#else
.text
# r2: cif->bytes
# r3: &ecif
# r4: ffi_prep_args
# r5: ret_type
# r6: ecif.rvalue
# ov: fn
# This assumes we are using gas.
.globl ffi_call_SYSV
.type ffi_call_SYSV,%function
ffi_call_SYSV:
.LFB1:
stmg %r6,%r15,48(%r15) # Save registers
.LCFI0:
larl %r13,.Lbase # Set up base register
lgr %r11,%r15 # Set up frame pointer
.LCFI1:
sgr %r15,%r2
aghi %r15,-160-80 # Allocate stack
lgr %r8,%r6 # Save ecif.rvalue
llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
lg %r7,160(%r11) # Load function address
stg %r11,0(%r15) # Set up back chain
aghi %r11,-80 # Register save area
.LCFI2:
la %r2,160(%r15) # Save area
# r3 already holds &ecif
basr %r14,%r4 # Call ffi_prep_args
lmg %r2,%r6,0(%r11) # Load arguments
ld %f0,48(%r11)
ld %f2,56(%r11)
ld %f4,64(%r11)
ld %f6,72(%r11)
la %r14,0(%r13,%r9) # Set return address
br %r7 # ... and call function
.Lbase:
.LretNone: # Return void
lg %r4,80+112(%r11)
lmg %r6,%r15,80+48(%r11)
br %r4
.LretFloat:
lg %r4,80+112(%r11)
ste %f0,0(%r8) # Return float
lmg %r6,%r15,80+48(%r11)
br %r4
.LretDouble:
lg %r4,80+112(%r11)
std %f0,0(%r8) # Return double
lmg %r6,%r15,80+48(%r11)
br %r4
.LretInt32:
lg %r4,80+112(%r11)
st %r2,0(%r8) # Return int
lmg %r6,%r15,80+48(%r11)
br %r4
.LretInt64:
lg %r4,80+112(%r11)
stg %r2,0(%r8) # Return long
lmg %r6,%r15,80+48(%r11)
br %r4
.Ltable:
.byte .LretNone-.Lbase # FFI390_RET_VOID
.byte .LretNone-.Lbase # FFI390_RET_STRUCT
.byte .LretFloat-.Lbase # FFI390_RET_FLOAT
.byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
.byte .LretInt32-.Lbase # FFI390_RET_INT32
.byte .LretInt64-.Lbase # FFI390_RET_INT64
.LFE1:
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
.globl ffi_closure_SYSV
.type ffi_closure_SYSV,%function
ffi_closure_SYSV:
.LFB2:
stmg %r14,%r15,112(%r15) # Save registers
.LCFI10:
stmg %r2,%r6,16(%r15) # Save arguments
std %f0,128(%r15)
std %f2,136(%r15)
std %f4,144(%r15)
std %f6,152(%r15)
lgr %r1,%r15 # Set up stack frame
aghi %r15,-160
.LCFI11:
lgr %r2,%r0 # Closure
la %r3,16(%r1) # GPRs
la %r4,128(%r1) # FPRs
la %r5,160(%r1) # Overflow
stg %r1,0(%r15) # Set up back chain
brasl %r14,ffi_closure_helper_SYSV # Call helper
lg %r14,160+112(%r15)
ld %f0,160+128(%r15) # Load return registers
lg %r2,160+16(%r15)
la %r15,160(%r15)
br %r14
.LFE2:
.ffi_closure_SYSV_end:
.size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
.section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
.LSCIE1:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.uleb128 0x1 # CIE Code Alignment Factor
.sleb128 -8 # CIE Data Alignment Factor
.byte 0xe # CIE RA Column
.uleb128 0x1 # Augmentation size
.byte 0x1b # FDE Encoding (pcrel sdata4)
.byte 0xc # DW_CFA_def_cfa
.uleb128 0xf
.uleb128 0xa0
.align 8
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 # FDE Length
.LASFDE1:
.4byte .LASFDE1-.Lframe1 # FDE CIE offset
.4byte .LFB1-. # FDE initial location
.4byte .LFE1-.LFB1 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI0-.LFB1
.byte 0x8f # DW_CFA_offset, column 0xf
.uleb128 0x5
.byte 0x8e # DW_CFA_offset, column 0xe
.uleb128 0x6
.byte 0x8d # DW_CFA_offset, column 0xd
.uleb128 0x7
.byte 0x8c # DW_CFA_offset, column 0xc
.uleb128 0x8
.byte 0x8b # DW_CFA_offset, column 0xb
.uleb128 0x9
.byte 0x8a # DW_CFA_offset, column 0xa
.uleb128 0xa
.byte 0x89 # DW_CFA_offset, column 0x9
.uleb128 0xb
.byte 0x88 # DW_CFA_offset, column 0x8
.uleb128 0xc
.byte 0x87 # DW_CFA_offset, column 0x7
.uleb128 0xd
.byte 0x86 # DW_CFA_offset, column 0x6
.uleb128 0xe
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI1-.LCFI0
.byte 0xd # DW_CFA_def_cfa_register
.uleb128 0xb
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI2-.LCFI1
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0xf0
.align 8
.LEFDE1:
.LSFDE2:
.4byte .LEFDE2-.LASFDE2 # FDE Length
.LASFDE2:
.4byte .LASFDE2-.Lframe1 # FDE CIE offset
.4byte .LFB2-. # FDE initial location
.4byte .LFE2-.LFB2 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI10-.LFB2
.byte 0x8f # DW_CFA_offset, column 0xf
.uleb128 0x5
.byte 0x8e # DW_CFA_offset, column 0xe
.uleb128 0x6
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI11-.LCFI10
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0x140
.align 8
.LEFDE2:
#endif

713
libffi/src/sh/ffi.c Normal file
View File

@@ -0,0 +1,713 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006 Kaz Kojima
SuperH 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#define NGREGARG 4
#if defined(__SH4__)
#define NFREGARG 8
#endif
#if defined(__HITACHI__)
#define STRUCT_VALUE_ADDRESS_WITH_ARG 1
#else
#define STRUCT_VALUE_ADDRESS_WITH_ARG 0
#endif
/* If the structure has essentialy an unique element, return its type. */
static int
simple_type (ffi_type *arg)
{
if (arg->type != FFI_TYPE_STRUCT)
return arg->type;
else if (arg->elements[1])
return FFI_TYPE_STRUCT;
return simple_type (arg->elements[0]);
}
static int
return_type (ffi_type *arg)
{
unsigned short type;
if (arg->type != FFI_TYPE_STRUCT)
return arg->type;
type = simple_type (arg->elements[0]);
if (! arg->elements[1])
{
switch (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:
return FFI_TYPE_INT;
default:
return type;
}
}
/* gcc uses r0/r1 pair for some kind of structures. */
if (arg->size <= 2 * sizeof (int))
{
int i = 0;
ffi_type *e;
while ((e = arg->elements[i++]))
{
type = simple_type (e);
switch (type)
{
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_INT:
case FFI_TYPE_FLOAT:
return FFI_TYPE_UINT64;
default:
break;
}
}
}
return FFI_TYPE_STRUCT;
}
/* 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)
{
register unsigned int i;
register int tmp;
register unsigned int avn;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
int greg, ireg;
#if defined(__SH4__)
int freg = 0;
#endif
tmp = 0;
argp = stack;
if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
{
*(void **) argp = ecif->rvalue;
argp += 4;
ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
}
else
ireg = 0;
/* Set arguments for registers. */
greg = ireg;
avn = ecif->cif->nargs;
p_argv = ecif->avalue;
for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
{
size_t z;
z = (*p_arg)->size;
if (z < sizeof(int))
{
if (greg++ >= NGREGARG)
continue;
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);
break;
case FFI_TYPE_STRUCT:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
argp += z;
}
else if (z == sizeof(int))
{
#if defined(__SH4__)
if ((*p_arg)->type == FFI_TYPE_FLOAT)
{
if (freg++ >= NFREGARG)
continue;
}
else
#endif
{
if (greg++ >= NGREGARG)
continue;
}
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
argp += z;
}
#if defined(__SH4__)
else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
{
if (freg + 1 >= NFREGARG)
continue;
freg = (freg + 1) & ~1;
freg += 2;
memcpy (argp, *p_argv, z);
argp += z;
}
#endif
else
{
int n = (z + sizeof (int) - 1) / sizeof (int);
#if defined(__SH4__)
if (greg + n - 1 >= NGREGARG)
continue;
#else
if (greg >= NGREGARG)
continue;
#endif
greg += n;
memcpy (argp, *p_argv, z);
argp += n * sizeof (int);
}
}
/* Set arguments on stack. */
greg = ireg;
#if defined(__SH4__)
freg = 0;
#endif
p_argv = ecif->avalue;
for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
{
size_t z;
z = (*p_arg)->size;
if (z < sizeof(int))
{
if (greg++ < NGREGARG)
continue;
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);
break;
case FFI_TYPE_STRUCT:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
argp += z;
}
else if (z == sizeof(int))
{
#if defined(__SH4__)
if ((*p_arg)->type == FFI_TYPE_FLOAT)
{
if (freg++ < NFREGARG)
continue;
}
else
#endif
{
if (greg++ < NGREGARG)
continue;
}
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
argp += z;
}
#if defined(__SH4__)
else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
{
if (freg + 1 < NFREGARG)
{
freg = (freg + 1) & ~1;
freg += 2;
continue;
}
memcpy (argp, *p_argv, z);
argp += z;
}
#endif
else
{
int n = (z + sizeof (int) - 1) / sizeof (int);
if (greg + n - 1 < NGREGARG)
{
greg += n;
continue;
}
#if (! defined(__SH4__))
else if (greg < NGREGARG)
{
greg = NGREGARG;
continue;
}
#endif
memcpy (argp, *p_argv, z);
argp += n * sizeof (int);
}
}
return;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
int i, j;
int size, type;
int n, m;
int greg;
#if defined(__SH4__)
int freg = 0;
#endif
cif->flags = 0;
greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
#if defined(__SH4__)
for (i = j = 0; i < cif->nargs && j < 12; i++)
{
type = (cif->arg_types)[i]->type;
switch (type)
{
case FFI_TYPE_FLOAT:
if (freg >= NFREGARG)
continue;
freg++;
cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
j++;
break;
case FFI_TYPE_DOUBLE:
if ((freg + 1) >= NFREGARG)
continue;
freg = (freg + 1) & ~1;
freg += 2;
cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
j++;
break;
default:
size = (cif->arg_types)[i]->size;
n = (size + sizeof (int) - 1) / sizeof (int);
if (greg + n - 1 >= NGREGARG)
continue;
greg += n;
for (m = 0; m < n; m++)
cif->flags += FFI_TYPE_INT << (2 * j++);
break;
}
}
#else
for (i = j = 0; i < cif->nargs && j < 4; i++)
{
size = (cif->arg_types)[i]->size;
n = (size + sizeof (int) - 1) / sizeof (int);
if (greg >= NGREGARG)
continue;
else if (greg + n - 1 >= NGREGARG)
n = NGREGARG - greg;
greg += n;
for (m = 0; m < n; m++)
cif->flags += FFI_TYPE_INT << (2 * j++);
}
#endif
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_STRUCT:
cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
break;
case FFI_TYPE_VOID:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags += (unsigned) cif->rtype->type << 24;
break;
default:
cif->flags += FFI_TYPE_INT << 24;
break;
}
return FFI_OK;
}
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)());
void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{
extended_cif ecif;
UINT64 trvalue;
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 (cif->rtype->type == FFI_TYPE_STRUCT
&& return_type (cif->rtype) != FFI_TYPE_STRUCT)
ecif.rvalue = &trvalue;
else 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;
}
if (rvalue
&& cif->rtype->type == FFI_TYPE_STRUCT
&& return_type (cif->rtype) != FFI_TYPE_STRUCT)
memcpy (rvalue, &trvalue, cif->rtype->size);
}
extern void ffi_closure_SYSV (void);
#if defined(__SH4__)
extern void __ic_invalidate (void *line);
#endif
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
unsigned int *tramp;
unsigned short insn;
FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
tramp = (unsigned int *) &closure->tramp[0];
/* Set T bit if the function returns a struct pointed with R2. */
insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT
? 0x0018 /* sett */
: 0x0008 /* clrt */);
#ifdef __LITTLE_ENDIAN__
tramp[0] = 0xd301d102;
tramp[1] = 0x0000412b | (insn << 16);
#else
tramp[0] = 0xd102d301;
tramp[1] = 0x412b0000 | insn;
#endif
*(void **) &tramp[2] = (void *)closure; /* ctx */
*(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
#if defined(__SH4__)
/* Flush the icache. */
__ic_invalidate(&closure->tramp[0]);
#endif
return FFI_OK;
}
/* Basically the trampoline invokes ffi_closure_SYSV, and on
* entry, r3 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.
*/
#ifdef __LITTLE_ENDIAN__
#define OFS_INT8 0
#define OFS_INT16 0
#else
#define OFS_INT8 3
#define OFS_INT16 2
#endif
int
ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
unsigned long *pgr, unsigned long *pfr,
unsigned long *pst)
{
void **avalue;
ffi_type **p_arg;
int i, avn;
int ireg, greg = 0;
#if defined(__SH4__)
int freg = 0;
#endif
ffi_cif *cif;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
/* 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 && STRUCT_VALUE_ADDRESS_WITH_ARG)
{
rvalue = (void *) *pgr++;
ireg = 1;
}
else
ireg = 0;
cif = closure->cif;
greg = ireg;
avn = cif->nargs;
/* Grab the addresses of the arguments from the stack frame. */
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
{
size_t z;
z = (*p_arg)->size;
if (z < sizeof(int))
{
if (greg++ >= NGREGARG)
continue;
z = sizeof(int);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
avalue[i] = (((char *)pgr) + OFS_INT8);
break;
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
avalue[i] = (((char *)pgr) + OFS_INT16);
break;
case FFI_TYPE_STRUCT:
avalue[i] = pgr;
break;
default:
FFI_ASSERT(0);
}
pgr++;
}
else if (z == sizeof(int))
{
#if defined(__SH4__)
if ((*p_arg)->type == FFI_TYPE_FLOAT)
{
if (freg++ >= NFREGARG)
continue;
avalue[i] = pfr;
pfr++;
}
else
#endif
{
if (greg++ >= NGREGARG)
continue;
avalue[i] = pgr;
pgr++;
}
}
#if defined(__SH4__)
else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
{
if (freg + 1 >= NFREGARG)
continue;
if (freg & 1)
pfr++;
freg = (freg + 1) & ~1;
freg += 2;
avalue[i] = pfr;
pfr += 2;
}
#endif
else
{
int n = (z + sizeof (int) - 1) / sizeof (int);
#if defined(__SH4__)
if (greg + n - 1 >= NGREGARG)
continue;
#else
if (greg >= NGREGARG)
continue;
#endif
greg += n;
avalue[i] = pgr;
pgr += n;
}
}
greg = ireg;
#if defined(__SH4__)
freg = 0;
#endif
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
{
size_t z;
z = (*p_arg)->size;
if (z < sizeof(int))
{
if (greg++ < NGREGARG)
continue;
z = sizeof(int);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
avalue[i] = (((char *)pst) + OFS_INT8);
break;
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
avalue[i] = (((char *)pst) + OFS_INT16);
break;
case FFI_TYPE_STRUCT:
avalue[i] = pst;
break;
default:
FFI_ASSERT(0);
}
pst++;
}
else if (z == sizeof(int))
{
#if defined(__SH4__)
if ((*p_arg)->type == FFI_TYPE_FLOAT)
{
if (freg++ < NFREGARG)
continue;
}
else
#endif
{
if (greg++ < NGREGARG)
continue;
}
avalue[i] = pst;
pst++;
}
#if defined(__SH4__)
else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
{
if (freg + 1 < NFREGARG)
{
freg = (freg + 1) & ~1;
freg += 2;
continue;
}
avalue[i] = pst;
pst += 2;
}
#endif
else
{
int n = (z + sizeof (int) - 1) / sizeof (int);
if (greg + n - 1 < NGREGARG)
{
greg += n;
continue;
}
#if (! defined(__SH4__))
else if (greg < NGREGARG)
{
greg += n;
pst += greg - NGREGARG;
continue;
}
#endif
avalue[i] = pst;
pst += n;
}
}
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_SYSV how to perform return type promotions. */
return return_type (cif->rtype);
}

48
libffi/src/sh/ffitarget.h Normal file
View File

@@ -0,0 +1,48 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for SuperH.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- Generic type definitions ----------------------------------------- */
#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
#define FFI_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 16
#define FFI_NATIVE_RAW_API 0
#endif

845
libffi/src/sh/sysv.S Normal file
View File

@@ -0,0 +1,845 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 2002, 2003, 2004, 2006 Kaz Kojima
SuperH 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 <fficonfig.h>
#include <ffi.h>
#ifdef HAVE_MACHINE_ASM_H
#include <machine/asm.h>
#else
/* XXX these lose for some platforms, I'm sure. */
#define CNAME(x) x
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
#endif
#if defined(__HITACHI__)
#define STRUCT_VALUE_ADDRESS_WITH_ARG 1
#else
#define STRUCT_VALUE_ADDRESS_WITH_ARG 0
#endif
.text
# r4: ffi_prep_args
# r5: &ecif
# r6: bytes
# r7: flags
# sp+0: rvalue
# sp+4: fn
# This assumes we are using gas.
ENTRY(ffi_call_SYSV)
# Save registers
.LFB1:
mov.l r8,@-r15
.LCFI0:
mov.l r9,@-r15
.LCFI1:
mov.l r10,@-r15
.LCFI2:
mov.l r12,@-r15
.LCFI3:
mov.l r14,@-r15
.LCFI4:
sts.l pr,@-r15
.LCFI5:
mov r15,r14
.LCFI6:
#if defined(__SH4__)
mov r6,r8
mov r7,r9
sub r6,r15
add #-16,r15
mov #~7,r0
and r0,r15
mov r4,r0
jsr @r0
mov r15,r4
mov r9,r1
shlr8 r9
shlr8 r9
shlr8 r9
mov #FFI_TYPE_STRUCT,r2
cmp/eq r2,r9
bf 1f
#if STRUCT_VALUE_ADDRESS_WITH_ARG
mov.l @r15+,r4
bra 2f
mov #5,r2
#else
mov.l @r15+,r10
#endif
1:
mov #4,r2
2:
mov #4,r3
L_pass:
cmp/pl r8
bf L_call_it
mov r1,r0
and #3,r0
L_pass_d:
cmp/eq #FFI_TYPE_DOUBLE,r0
bf L_pass_f
mov r3,r0
and #1,r0
tst r0,r0
bt 1f
add #1,r3
1:
mov #12,r0
cmp/hs r0,r3
bt/s 3f
shlr2 r1
bsr L_pop_d
nop
3:
add #2,r3
bra L_pass
add #-8,r8
L_pop_d:
mov r3,r0
add r0,r0
add r3,r0
add #-12,r0
braf r0
nop
#ifdef __LITTLE_ENDIAN__
fmov.s @r15+,fr5
rts
fmov.s @r15+,fr4
fmov.s @r15+,fr7
rts
fmov.s @r15+,fr6
fmov.s @r15+,fr9
rts
fmov.s @r15+,fr8
fmov.s @r15+,fr11
rts
fmov.s @r15+,fr10
#else
fmov.s @r15+,fr4
rts
fmov.s @r15+,fr5
fmov.s @r15+,fr6
rts
fmov.s @r15+,fr7
fmov.s @r15+,fr8
rts
fmov.s @r15+,fr9
fmov.s @r15+,fr10
rts
fmov.s @r15+,fr11
#endif
L_pass_f:
cmp/eq #FFI_TYPE_FLOAT,r0
bf L_pass_i
mov #12,r0
cmp/hs r0,r3
bt/s 2f
shlr2 r1
bsr L_pop_f
nop
2:
add #1,r3
bra L_pass
add #-4,r8
L_pop_f:
mov r3,r0
shll2 r0
add #-16,r0
braf r0
nop
#ifdef __LITTLE_ENDIAN__
rts
fmov.s @r15+,fr5
rts
fmov.s @r15+,fr4
rts
fmov.s @r15+,fr7
rts
fmov.s @r15+,fr6
rts
fmov.s @r15+,fr9
rts
fmov.s @r15+,fr8
rts
fmov.s @r15+,fr11
rts
fmov.s @r15+,fr10
#else
rts
fmov.s @r15+,fr4
rts
fmov.s @r15+,fr5
rts
fmov.s @r15+,fr6
rts
fmov.s @r15+,fr7
rts
fmov.s @r15+,fr8
rts
fmov.s @r15+,fr9
rts
fmov.s @r15+,fr10
rts
fmov.s @r15+,fr11
#endif
L_pass_i:
cmp/eq #FFI_TYPE_INT,r0
bf L_call_it
mov #8,r0
cmp/hs r0,r2
bt/s 2f
shlr2 r1
bsr L_pop_i
nop
2:
add #1,r2
bra L_pass
add #-4,r8
L_pop_i:
mov r2,r0
shll2 r0
add #-16,r0
braf r0
nop
rts
mov.l @r15+,r4
rts
mov.l @r15+,r5
rts
mov.l @r15+,r6
rts
mov.l @r15+,r7
L_call_it:
# call function
#if (! STRUCT_VALUE_ADDRESS_WITH_ARG)
mov r10, r2
#endif
mov.l @(28,r14),r1
jsr @r1
nop
L_ret_d:
mov #FFI_TYPE_DOUBLE,r2
cmp/eq r2,r9
bf L_ret_ll
mov.l @(24,r14),r1
#ifdef __LITTLE_ENDIAN__
fmov.s fr1,@r1
add #4,r1
bra L_epilogue
fmov.s fr0,@r1
#else
fmov.s fr0,@r1
add #4,r1
bra L_epilogue
fmov.s fr1,@r1
#endif
L_ret_ll:
mov #FFI_TYPE_SINT64,r2
cmp/eq r2,r9
bt/s 1f
mov #FFI_TYPE_UINT64,r2
cmp/eq r2,r9
bf L_ret_f
1:
mov.l @(24,r14),r2
mov.l r0,@r2
bra L_epilogue
mov.l r1,@(4,r2)
L_ret_f:
mov #FFI_TYPE_FLOAT,r2
cmp/eq r2,r9
bf L_ret_i
mov.l @(24,r14),r1
bra L_epilogue
fmov.s fr0,@r1
L_ret_i:
mov #FFI_TYPE_INT,r2
cmp/eq r2,r9
bf L_epilogue
mov.l @(24,r14),r1
bra L_epilogue
mov.l r0,@r1
L_epilogue:
# Remove the space we pushed for the args
mov r14,r15
lds.l @r15+,pr
mov.l @r15+,r14
mov.l @r15+,r12
mov.l @r15+,r10
mov.l @r15+,r9
rts
mov.l @r15+,r8
#else
mov r6,r8
mov r7,r9
sub r6,r15
add #-16,r15
mov #~7,r0
and r0,r15
mov r4,r0
jsr @r0
mov r15,r4
mov r9,r3
shlr8 r9
shlr8 r9
shlr8 r9
mov #FFI_TYPE_STRUCT,r2
cmp/eq r2,r9
bf 1f
#if STRUCT_VALUE_ADDRESS_WITH_ARG
mov.l @r15+,r4
bra 2f
mov #5,r2
#else
mov.l @r15+,r10
#endif
1:
mov #4,r2
2:
L_pass:
cmp/pl r8
bf L_call_it
mov r3,r0
and #3,r0
L_pass_d:
cmp/eq #FFI_TYPE_DOUBLE,r0
bf L_pass_i
mov r15,r0
and #7,r0
tst r0,r0
bt 1f
add #4,r15
1:
mov #8,r0
cmp/hs r0,r2
bt/s 2f
shlr2 r3
bsr L_pop_d
nop
2:
add #2,r2
bra L_pass
add #-8,r8
L_pop_d:
mov r2,r0
add r0,r0
add r2,r0
add #-12,r0
add r0,r0
braf r0
nop
mov.l @r15+,r4
rts
mov.l @r15+,r5
mov.l @r15+,r5
rts
mov.l @r15+,r6
mov.l @r15+,r6
rts
mov.l @r15+,r7
rts
mov.l @r15+,r7
L_pass_i:
cmp/eq #FFI_TYPE_INT,r0
bf L_call_it
mov #8,r0
cmp/hs r0,r2
bt/s 2f
shlr2 r3
bsr L_pop_i
nop
2:
add #1,r2
bra L_pass
add #-4,r8
L_pop_i:
mov r2,r0
shll2 r0
add #-16,r0
braf r0
nop
rts
mov.l @r15+,r4
rts
mov.l @r15+,r5
rts
mov.l @r15+,r6
rts
mov.l @r15+,r7
L_call_it:
# call function
#if (! STRUCT_VALUE_ADDRESS_WITH_ARG)
mov r10, r2
#endif
mov.l @(28,r14),r1
jsr @r1
nop
L_ret_d:
mov #FFI_TYPE_DOUBLE,r2
cmp/eq r2,r9
bf L_ret_ll
mov.l @(24,r14),r2
mov.l r0,@r2
bra L_epilogue
mov.l r1,@(4,r2)
L_ret_ll:
mov #FFI_TYPE_SINT64,r2
cmp/eq r2,r9
bt/s 1f
mov #FFI_TYPE_UINT64,r2
cmp/eq r2,r9
bf L_ret_i
1:
mov.l @(24,r14),r2
mov.l r0,@r2
bra L_epilogue
mov.l r1,@(4,r2)
L_ret_i:
mov #FFI_TYPE_FLOAT,r2
cmp/eq r2,r9
bt 1f
mov #FFI_TYPE_INT,r2
cmp/eq r2,r9
bf L_epilogue
1:
mov.l @(24,r14),r1
bra L_epilogue
mov.l r0,@r1
L_epilogue:
# Remove the space we pushed for the args
mov r14,r15
lds.l @r15+,pr
mov.l @r15+,r14
mov.l @r15+,r12
mov.l @r15+,r10
mov.l @r15+,r9
rts
mov.l @r15+,r8
#endif
.LFE1:
.ffi_call_SYSV_end:
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
.globl ffi_closure_helper_SYSV
ENTRY(ffi_closure_SYSV)
.LFB2:
mov.l r7,@-r15
.LCFI7:
mov.l r6,@-r15
.LCFI8:
mov.l r5,@-r15
.LCFI9:
mov.l r4,@-r15
.LCFIA:
mov.l r14,@-r15
.LCFIB:
sts.l pr,@-r15
/* Stack layout:
xx bytes (on stack parameters)
16 bytes (register parameters)
4 bytes (saved frame pointer)
4 bytes (saved return address)
32 bytes (floating register parameters, SH-4 only)
8 bytes (result)
4 bytes (pad)
4 bytes (5th arg)
<- new stack pointer
*/
.LCFIC:
#if defined(__SH4__)
add #-48,r15
#else
add #-16,r15
#endif
.LCFID:
mov r15,r14
.LCFIE:
#if defined(__SH4__)
mov r14,r1
add #48,r1
#ifdef __LITTLE_ENDIAN__
fmov.s fr10,@-r1
fmov.s fr11,@-r1
fmov.s fr8,@-r1
fmov.s fr9,@-r1
fmov.s fr6,@-r1
fmov.s fr7,@-r1
fmov.s fr4,@-r1
fmov.s fr5,@-r1
#else
fmov.s fr11,@-r1
fmov.s fr10,@-r1
fmov.s fr9,@-r1
fmov.s fr8,@-r1
fmov.s fr7,@-r1
fmov.s fr6,@-r1
fmov.s fr5,@-r1
fmov.s fr4,@-r1
#endif
mov r1,r7
mov r14,r6
add #56,r6
#else
mov r14,r6
add #24,r6
#endif
bt/s 10f
mov r2, r5
mov r14,r1
add #8,r1
mov r1,r5
10:
mov r14,r1
#if defined(__SH4__)
add #72,r1
#else
add #40,r1
#endif
mov.l r1,@r14
#ifdef PIC
mov.l L_got,r1
mova L_got,r0
add r0,r1
mov.l L_helper,r0
add r1,r0
#else
mov.l L_helper,r0
#endif
jsr @r0
mov r3,r4
shll r0
mov r0,r1
mova L_table,r0
add r1,r0
mov.w @r0,r0
mov r14,r2
braf r0
add #8,r2
0:
.align 2
#ifdef PIC
L_got:
.long _GLOBAL_OFFSET_TABLE_
L_helper:
.long ffi_closure_helper_SYSV@GOTOFF
#else
L_helper:
.long ffi_closure_helper_SYSV
#endif
L_table:
.short L_case_v - 0b /* FFI_TYPE_VOID */
.short L_case_i - 0b /* FFI_TYPE_INT */
#if defined(__SH4__)
.short L_case_f - 0b /* FFI_TYPE_FLOAT */
.short L_case_d - 0b /* FFI_TYPE_DOUBLE */
.short L_case_d - 0b /* FFI_TYPE_LONGDOUBLE */
#else
.short L_case_i - 0b /* FFI_TYPE_FLOAT */
.short L_case_ll - 0b /* FFI_TYPE_DOUBLE */
.short L_case_ll - 0b /* FFI_TYPE_LONGDOUBLE */
#endif
.short L_case_uq - 0b /* FFI_TYPE_UINT8 */
.short L_case_q - 0b /* FFI_TYPE_SINT8 */
.short L_case_uh - 0b /* FFI_TYPE_UINT16 */
.short L_case_h - 0b /* FFI_TYPE_SINT16 */
.short L_case_i - 0b /* FFI_TYPE_UINT32 */
.short L_case_i - 0b /* FFI_TYPE_SINT32 */
.short L_case_ll - 0b /* FFI_TYPE_UINT64 */
.short L_case_ll - 0b /* FFI_TYPE_SINT64 */
.short L_case_v - 0b /* FFI_TYPE_STRUCT */
.short L_case_i - 0b /* FFI_TYPE_POINTER */
#if defined(__SH4__)
L_case_d:
#ifdef __LITTLE_ENDIAN__
fmov.s @r2+,fr1
bra L_case_v
fmov.s @r2,fr0
#else
fmov.s @r2+,fr0
bra L_case_v
fmov.s @r2,fr1
#endif
L_case_f:
bra L_case_v
fmov.s @r2,fr0
#endif
L_case_ll:
mov.l @r2+,r0
bra L_case_v
mov.l @r2,r1
L_case_i:
bra L_case_v
mov.l @r2,r0
L_case_q:
#ifdef __LITTLE_ENDIAN__
#else
add #3,r2
#endif
bra L_case_v
mov.b @r2,r0
L_case_uq:
#ifdef __LITTLE_ENDIAN__
#else
add #3,r2
#endif
mov.b @r2,r0
bra L_case_v
extu.b r0,r0
L_case_h:
#ifdef __LITTLE_ENDIAN__
#else
add #2,r2
#endif
bra L_case_v
mov.w @r2,r0
L_case_uh:
#ifdef __LITTLE_ENDIAN__
#else
add #2,r2
#endif
mov.w @r2,r0
extu.w r0,r0
/* fall through */
L_case_v:
#if defined(__SH4__)
add #48,r15
#else
add #16,r15
#endif
lds.l @r15+,pr
mov.l @r15+,r14
rts
add #16,r15
.LFE2:
.ffi_closure_SYSV_end:
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
.section ".eh_frame","aw",@progbits
__FRAME_BEGIN__:
.4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
.LSCIE1:
.4byte 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#ifdef PIC
.ascii "zR\0" /* CIE Augmentation */
#else
.byte 0x0 /* CIE Augmentation */
#endif
.byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
.byte 0x7c /* sleb128 -4; CIE Data Alignment Factor */
.byte 0x11 /* CIE RA Column */
#ifdef PIC
.uleb128 0x1 /* Augmentation size */
.byte 0x10 /* FDE Encoding (pcrel) */
#endif
.byte 0xc /* DW_CFA_def_cfa */
.byte 0xf /* uleb128 0xf */
.byte 0x0 /* uleb128 0x0 */
.align 2
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.4byte .LASFDE1-__FRAME_BEGIN__ /* FDE CIE offset */
#ifdef PIC
.4byte .LFB1-. /* FDE initial location */
#else
.4byte .LFB1 /* FDE initial location */
#endif
.4byte .LFE1-.LFB1 /* FDE address range */
#ifdef PIC
.uleb128 0x0 /* Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI0-.LFB1
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x4 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI1-.LCFI0
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x8 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI2-.LCFI1
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0xc /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI3-.LCFI2
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x10 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI4-.LCFI3
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x14 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI5-.LCFI4
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x18 /* uleb128 0x4 */
.byte 0x91 /* DW_CFA_offset, column 0x11 */
.byte 0x6 /* uleb128 0x6 */
.byte 0x8e /* DW_CFA_offset, column 0xe */
.byte 0x5 /* uleb128 0x5 */
.byte 0x8c /* DW_CFA_offset, column 0xc */
.byte 0x4 /* uleb128 0x4 */
.byte 0x8a /* DW_CFA_offset, column 0xa */
.byte 0x3 /* uleb128 0x3 */
.byte 0x89 /* DW_CFA_offset, column 0x9 */
.byte 0x2 /* uleb128 0x2 */
.byte 0x88 /* DW_CFA_offset, column 0x8 */
.byte 0x1 /* uleb128 0x1 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI6-.LCFI5
.byte 0xd /* DW_CFA_def_cfa_register */
.byte 0xe /* uleb128 0xe */
.align 2
.LEFDE1:
.LSFDE3:
.4byte .LEFDE3-.LASFDE3 /* FDE Length */
.LASFDE3:
.4byte .LASFDE3-__FRAME_BEGIN__ /* FDE CIE offset */
#ifdef PIC
.4byte .LFB2-. /* FDE initial location */
#else
.4byte .LFB2 /* FDE initial location */
#endif
.4byte .LFE2-.LFB2 /* FDE address range */
#ifdef PIC
.uleb128 0x0 /* Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI7-.LFB2
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x4 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI8-.LCFI7
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x8 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI9-.LCFI8
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0xc /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFIA-.LCFI9
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x10 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFIB-.LCFIA
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x14 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFIC-.LCFIB
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x18 /* uleb128 0x4 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFID-.LCFIC
.byte 0xe /* DW_CFA_def_cfa_offset */
#if defined(__SH4__)
.byte 24+48 /* uleb128 24+48 */
#else
.byte 24+16 /* uleb128 24+16 */
#endif
.byte 0x91 /* DW_CFA_offset, column 0x11 */
.byte 0x6 /* uleb128 0x6 */
.byte 0x8e /* DW_CFA_offset, column 0xe */
.byte 0x5 /* uleb128 0x5 */
.byte 0x84 /* DW_CFA_offset, column 0x4 */
.byte 0x4 /* uleb128 0x4 */
.byte 0x85 /* DW_CFA_offset, column 0x5 */
.byte 0x3 /* uleb128 0x3 */
.byte 0x86 /* DW_CFA_offset, column 0x6 */
.byte 0x2 /* uleb128 0x2 */
.byte 0x87 /* DW_CFA_offset, column 0x7 */
.byte 0x1 /* uleb128 0x1 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFIE-.LCFID
.byte 0xd /* DW_CFA_def_cfa_register */
.byte 0xe /* uleb128 0xe */
.align 2
.LEFDE3:

455
libffi/src/sh64/ffi.c Normal file
View File

@@ -0,0 +1,455 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2003, 2004, 2006 Kaz Kojima
SuperH SHmedia 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#define NGREGARG 8
#define NFREGARG 12
static int
return_type (ffi_type *arg)
{
if (arg->type != FFI_TYPE_STRUCT)
return arg->type;
/* gcc uses r2 if the result can be packed in on register. */
if (arg->size <= sizeof (UINT8))
return FFI_TYPE_UINT8;
else if (arg->size <= sizeof (UINT16))
return FFI_TYPE_UINT16;
else if (arg->size <= sizeof (UINT32))
return FFI_TYPE_UINT32;
else if (arg->size <= sizeof (UINT64))
return FFI_TYPE_UINT64;
return FFI_TYPE_STRUCT;
}
/* 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)
{
register unsigned int i;
register unsigned int avn;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
{
*(void **) argp = ecif->rvalue;
argp += sizeof (UINT64);
}
avn = ecif->cif->nargs;
p_argv = ecif->avalue;
for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
{
size_t z;
int align;
z = (*p_arg)->size;
align = (*p_arg)->alignment;
if (z < sizeof (UINT32))
{
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
break;
case FFI_TYPE_UINT8:
*(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
break;
case FFI_TYPE_SINT16:
*(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
break;
case FFI_TYPE_UINT16:
*(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
break;
case FFI_TYPE_STRUCT:
memcpy (argp, *p_argv, z);
break;
default:
FFI_ASSERT(0);
}
argp += sizeof (UINT64);
}
else if (z == sizeof (UINT32) && align == sizeof (UINT32))
{
switch ((*p_arg)->type)
{
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
*(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
break;
case FFI_TYPE_FLOAT:
case FFI_TYPE_POINTER:
case FFI_TYPE_UINT32:
case FFI_TYPE_STRUCT:
*(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
break;
default:
FFI_ASSERT(0);
break;
}
argp += sizeof (UINT64);
}
else if (z == sizeof (UINT64)
&& align == sizeof (UINT64)
&& ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
{
*(UINT64 *) argp = *(UINT64 *) (*p_argv);
argp += sizeof (UINT64);
}
else
{
int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
memcpy (argp, *p_argv, z);
argp += n * sizeof (UINT64);
}
}
return;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
int i, j;
int size, type;
int n, m;
int greg;
int freg;
int fpair = -1;
greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
freg = 0;
cif->flags2 = 0;
for (i = j = 0; i < cif->nargs; i++)
{
type = (cif->arg_types)[i]->type;
switch (type)
{
case FFI_TYPE_FLOAT:
greg++;
cif->bytes += sizeof (UINT64) - sizeof (float);
if (freg >= NFREGARG - 1)
continue;
if (fpair < 0)
{
fpair = freg;
freg += 2;
}
else
fpair = -1;
cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
break;
case FFI_TYPE_DOUBLE:
if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
continue;
if ((freg + 1) < NFREGARG)
{
freg += 2;
cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
}
else
cif->flags2 += FFI_TYPE_INT << (2 * j++);
break;
default:
size = (cif->arg_types)[i]->size;
if (size < sizeof (UINT64))
cif->bytes += sizeof (UINT64) - size;
n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
if (greg >= NGREGARG)
continue;
else if (greg + n - 1 >= NGREGARG)
greg = NGREGARG;
else
greg += n;
for (m = 0; m < n; m++)
cif->flags2 += FFI_TYPE_INT << (2 * j++);
break;
}
}
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_STRUCT:
cif->flags = return_type (cif->rtype);
break;
case FFI_TYPE_VOID:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags = cif->rtype->type;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, long long, unsigned *,
void (*fn)());
void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{
extended_cif ecif;
UINT64 trvalue;
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 (cif->rtype->type == FFI_TYPE_STRUCT
&& return_type (cif->rtype) != FFI_TYPE_STRUCT)
ecif.rvalue = &trvalue;
else 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, cif->flags2,
ecif.rvalue, fn);
break;
default:
FFI_ASSERT(0);
break;
}
if (rvalue
&& cif->rtype->type == FFI_TYPE_STRUCT
&& return_type (cif->rtype) != FFI_TYPE_STRUCT)
memcpy (rvalue, &trvalue, cif->rtype->size);
}
extern void ffi_closure_SYSV (void);
extern void __ic_invalidate (void *line);
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];
/* Since ffi_closure is an aligned object, the ffi trampoline is
called as an SHcompact code. Sigh.
SHcompact part:
mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
SHmedia part:
movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
#ifdef __LITTLE_ENDIAN__
tramp[0] = 0x7001c701;
tramp[1] = 0x0009402b;
#else
tramp[0] = 0xc7017001;
tramp[1] = 0x402b0009;
#endif
tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
tramp[4] = 0x6bf10600;
tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
tramp[7] = 0x4401fff0;
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* Flush the icache. */
asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
return FFI_OK;
}
/* Basically the trampoline invokes ffi_closure_SYSV, and on
* entry, r3 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, UINT64 *rvalue,
UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
{
void **avalue;
ffi_type **p_arg;
int i, avn;
int greg, freg;
ffi_cif *cif;
int fpair = -1;
cif = closure->cif;
avalue = alloca (cif->nargs * sizeof (void *));
/* Copy the caller's structure return value address so that the closure
returns the data directly to the caller. */
if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
{
rvalue = (UINT64 *) *pgr;
greg = 1;
}
else
greg = 0;
freg = 0;
cif = closure->cif;
avn = cif->nargs;
/* Grab the addresses of the arguments from the stack frame. */
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
{
size_t z;
void *p;
z = (*p_arg)->size;
if (z < sizeof (UINT32))
{
p = pgr + greg++;
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
case FFI_TYPE_STRUCT:
#ifdef __LITTLE_ENDIAN__
avalue[i] = p;
#else
avalue[i] = ((char *) p) + sizeof (UINT32) - z;
#endif
break;
default:
FFI_ASSERT(0);
}
}
else if (z == sizeof (UINT32))
{
if ((*p_arg)->type == FFI_TYPE_FLOAT)
{
if (freg < NFREGARG - 1)
{
if (fpair >= 0)
{
avalue[i] = (UINT32 *) pfr + fpair;
fpair = -1;
}
else
{
#ifdef __LITTLE_ENDIAN__
fpair = freg;
avalue[i] = (UINT32 *) pfr + (1 ^ freg);
#else
fpair = 1 ^ freg;
avalue[i] = (UINT32 *) pfr + freg;
#endif
freg += 2;
}
}
else
#ifdef __LITTLE_ENDIAN__
avalue[i] = pgr + greg;
#else
avalue[i] = (UINT32 *) (pgr + greg) + 1;
#endif
}
else
#ifdef __LITTLE_ENDIAN__
avalue[i] = pgr + greg;
#else
avalue[i] = (UINT32 *) (pgr + greg) + 1;
#endif
greg++;
}
else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
{
if (freg + 1 >= NFREGARG)
avalue[i] = pgr + greg;
else
{
avalue[i] = pfr + (freg >> 1);
freg += 2;
}
greg++;
}
else
{
int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
avalue[i] = pgr + greg;
greg += n;
}
}
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_SYSV how to perform return type promotions. */
return return_type (cif->rtype);
}

View File

@@ -0,0 +1,52 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for SuperH - SHmedia.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- Generic type definitions ----------------------------------------- */
#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;
#define FFI_EXTRA_CIF_FIELDS long long flags2
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 32
#define FFI_NATIVE_RAW_API 0
#endif

533
libffi/src/sh64/sysv.S Normal file
View File

@@ -0,0 +1,533 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 2003, 2004, 2006 Kaz Kojima
SuperH SHmedia 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 <fficonfig.h>
#include <ffi.h>
#ifdef HAVE_MACHINE_ASM_H
#include <machine/asm.h>
#else
/* XXX these lose for some platforms, I'm sure. */
#define CNAME(x) x
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
#endif
#ifdef __LITTLE_ENDIAN__
#define OFS_FLT 0
#else
#define OFS_FLT 4
#endif
.section .text..SHmedia32,"ax"
# r2: ffi_prep_args
# r3: &ecif
# r4: bytes
# r5: flags
# r6: flags2
# r7: rvalue
# r8: fn
# This assumes we are using gas.
.align 5
ENTRY(ffi_call_SYSV)
# Save registers
.LFB1:
addi.l r15, -48, r15
.LCFI0:
st.q r15, 40, r32
st.q r15, 32, r31
st.q r15, 24, r30
st.q r15, 16, r29
st.q r15, 8, r28
st.l r15, 4, r18
st.l r15, 0, r14
.LCFI1:
add.l r15, r63, r14
.LCFI2:
# add r4, r63, r28
add r5, r63, r29
add r6, r63, r30
add r7, r63, r31
add r8, r63, r32
addi r4, (64 + 7), r4
andi r4, ~7, r4
sub.l r15, r4, r15
ptabs/l r2, tr0
add r15, r63, r2
blink tr0, r18
addi r15, 64, r22
movi 0, r0
movi 0, r1
movi -1, r23
pt/l 1f, tr1
bnei/l r29, FFI_TYPE_STRUCT, tr1
ld.l r15, 0, r19
addi r15, 8, r15
addi r0, 1, r0
1:
.L_pass:
andi r30, 3, r20
shlri r30, 2, r30
pt/l .L_call_it, tr0
pt/l .L_pass_i, tr1
pt/l .L_pass_f, tr2
beqi/l r20, FFI_TYPE_VOID, tr0
beqi/l r20, FFI_TYPE_INT, tr1
beqi/l r20, FFI_TYPE_FLOAT, tr2
.L_pass_d:
addi r0, 1, r0
pt/l 3f, tr0
movi 12, r20
bge/l r1, r20, tr0
pt/l .L_pop_d, tr1
pt/l 2f, tr0
blink tr1, r63
2:
addi.l r15, 8, r15
3:
pt/l .L_pass, tr0
addi r1, 2, r1
blink tr0, r63
.L_pop_d:
pt/l .L_pop_d_tbl, tr1
gettr tr1, r20
shlli r1, 2, r21
add r20, r21, r20
ptabs/l r20, tr1
blink tr1, r63
.L_pop_d_tbl:
fld.d r15, 0, dr0
blink tr0, r63
fld.d r15, 0, dr2
blink tr0, r63
fld.d r15, 0, dr4
blink tr0, r63
fld.d r15, 0, dr6
blink tr0, r63
fld.d r15, 0, dr8
blink tr0, r63
fld.d r15, 0, dr10
blink tr0, r63
.L_pass_f:
addi r0, 1, r0
pt/l 3f, tr0
movi 12, r20
bge/l r1, r20, tr0
pt/l .L_pop_f, tr1
pt/l 2f, tr0
blink tr1, r63
2:
addi.l r15, 8, r15
3:
pt/l .L_pass, tr0
blink tr0, r63
.L_pop_f:
pt/l .L_pop_f_tbl, tr1
pt/l 5f, tr2
gettr tr1, r20
bge/l r23, r63, tr2
add r1, r63, r23
shlli r1, 3, r21
addi r1, 2, r1
add r20, r21, r20
ptabs/l r20, tr1
blink tr1, r63
5:
addi r23, 1, r21
movi -1, r23
shlli r21, 3, r21
add r20, r21, r20
ptabs/l r20, tr1
blink tr1, r63
.L_pop_f_tbl:
fld.s r15, OFS_FLT, fr0
blink tr0, r63
fld.s r15, OFS_FLT, fr1
blink tr0, r63
fld.s r15, OFS_FLT, fr2
blink tr0, r63
fld.s r15, OFS_FLT, fr3
blink tr0, r63
fld.s r15, OFS_FLT, fr4
blink tr0, r63
fld.s r15, OFS_FLT, fr5
blink tr0, r63
fld.s r15, OFS_FLT, fr6
blink tr0, r63
fld.s r15, OFS_FLT, fr7
blink tr0, r63
fld.s r15, OFS_FLT, fr8
blink tr0, r63
fld.s r15, OFS_FLT, fr9
blink tr0, r63
fld.s r15, OFS_FLT, fr10
blink tr0, r63
fld.s r15, OFS_FLT, fr11
blink tr0, r63
.L_pass_i:
pt/l 3f, tr0
movi 8, r20
bge/l r0, r20, tr0
pt/l .L_pop_i, tr1
pt/l 2f, tr0
blink tr1, r63
2:
addi.l r15, 8, r15
3:
pt/l .L_pass, tr0
addi r0, 1, r0
blink tr0, r63
.L_pop_i:
pt/l .L_pop_i_tbl, tr1
gettr tr1, r20
shlli r0, 3, r21
add r20, r21, r20
ptabs/l r20, tr1
blink tr1, r63
.L_pop_i_tbl:
ld.q r15, 0, r2
blink tr0, r63
ld.q r15, 0, r3
blink tr0, r63
ld.q r15, 0, r4
blink tr0, r63
ld.q r15, 0, r5
blink tr0, r63
ld.q r15, 0, r6
blink tr0, r63
ld.q r15, 0, r7
blink tr0, r63
ld.q r15, 0, r8
blink tr0, r63
ld.q r15, 0, r9
blink tr0, r63
.L_call_it:
# call function
pt/l 1f, tr1
bnei/l r29, FFI_TYPE_STRUCT, tr1
add r19, r63, r2
1:
add r22, r63, r15
ptabs/l r32, tr0
blink tr0, r18
pt/l .L_ret_i, tr0
pt/l .L_ret_ll, tr1
pt/l .L_ret_d, tr2
pt/l .L_ret_f, tr3
pt/l .L_epilogue, tr4
beqi/l r29, FFI_TYPE_INT, tr0
beqi/l r29, FFI_TYPE_UINT32, tr0
beqi/l r29, FFI_TYPE_SINT64, tr1
beqi/l r29, FFI_TYPE_UINT64, tr1
beqi/l r29, FFI_TYPE_DOUBLE, tr2
beqi/l r29, FFI_TYPE_FLOAT, tr3
pt/l .L_ret_q, tr0
pt/l .L_ret_h, tr1
beqi/l r29, FFI_TYPE_UINT8, tr0
beqi/l r29, FFI_TYPE_UINT16, tr1
blink tr4, r63
.L_ret_d:
fst.d r31, 0, dr0
blink tr4, r63
.L_ret_ll:
st.q r31, 0, r2
blink tr4, r63
.L_ret_f:
fst.s r31, OFS_FLT, fr0
blink tr4, r63
.L_ret_q:
st.b r31, 0, r2
blink tr4, r63
.L_ret_h:
st.w r31, 0, r2
blink tr4, r63
.L_ret_i:
st.l r31, 0, r2
# Fall
.L_epilogue:
# Remove the space we pushed for the args
add r14, r63, r15
ld.l r15, 0, r14
ld.l r15, 4, r18
ld.q r15, 8, r28
ld.q r15, 16, r29
ld.q r15, 24, r30
ld.q r15, 32, r31
ld.q r15, 40, r32
addi.l r15, 48, r15
ptabs r18, tr0
blink tr0, r63
.LFE1:
.ffi_call_SYSV_end:
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
.align 5
ENTRY(ffi_closure_SYSV)
.LFB2:
addi.l r15, -136, r15
.LCFI3:
st.l r15, 12, r18
st.l r15, 8, r14
st.l r15, 4, r12
.LCFI4:
add r15, r63, r14
.LCFI5:
/* Stack layout:
...
64 bytes (register parameters)
48 bytes (floating register parameters)
8 bytes (result)
4 bytes (r18)
4 bytes (r14)
4 bytes (r12)
4 bytes (for align)
<- new stack pointer
*/
fst.d r14, 24, dr0
fst.d r14, 32, dr2
fst.d r14, 40, dr4
fst.d r14, 48, dr6
fst.d r14, 56, dr8
fst.d r14, 64, dr10
st.q r14, 72, r2
st.q r14, 80, r3
st.q r14, 88, r4
st.q r14, 96, r5
st.q r14, 104, r6
st.q r14, 112, r7
st.q r14, 120, r8
st.q r14, 128, r9
add r1, r63, r2
addi r14, 16, r3
addi r14, 72, r4
addi r14, 24, r5
addi r14, 136, r6
#ifdef PIC
movi (((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) >> 16) & 65535), r12
shori ((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) & 65535), r12
.LPCS0: ptrel/u r12, tr0
movi ((ffi_closure_helper_SYSV@GOTPLT) & 65535), r1
gettr tr0, r12
ldx.l r1, r12, r1
ptabs r1, tr0
#else
pt/l ffi_closure_helper_SYSV, tr0
#endif
blink tr0, r18
shlli r2, 1, r1
movi (((datalabel .L_table) >> 16) & 65535), r2
shori ((datalabel .L_table) & 65535), r2
ldx.w r2, r1, r1
add r1, r2, r1
pt/l .L_case_v, tr1
ptabs r1, tr0
blink tr0, r63
.align 2
.L_table:
.word .L_case_v - datalabel .L_table /* FFI_TYPE_VOID */
.word .L_case_i - datalabel .L_table /* FFI_TYPE_INT */
.word .L_case_f - datalabel .L_table /* FFI_TYPE_FLOAT */
.word .L_case_d - datalabel .L_table /* FFI_TYPE_DOUBLE */
.word .L_case_d - datalabel .L_table /* FFI_TYPE_LONGDOUBLE */
.word .L_case_uq - datalabel .L_table /* FFI_TYPE_UINT8 */
.word .L_case_q - datalabel .L_table /* FFI_TYPE_SINT8 */
.word .L_case_uh - datalabel .L_table /* FFI_TYPE_UINT16 */
.word .L_case_h - datalabel .L_table /* FFI_TYPE_SINT16 */
.word .L_case_i - datalabel .L_table /* FFI_TYPE_UINT32 */
.word .L_case_i - datalabel .L_table /* FFI_TYPE_SINT32 */
.word .L_case_ll - datalabel .L_table /* FFI_TYPE_UINT64 */
.word .L_case_ll - datalabel .L_table /* FFI_TYPE_SINT64 */
.word .L_case_v - datalabel .L_table /* FFI_TYPE_STRUCT */
.word .L_case_i - datalabel .L_table /* FFI_TYPE_POINTER */
.align 2
.L_case_d:
fld.d r14, 16, dr0
blink tr1, r63
.L_case_f:
fld.s r14, 16, fr0
blink tr1, r63
.L_case_ll:
ld.q r14, 16, r2
blink tr1, r63
.L_case_i:
ld.l r14, 16, r2
blink tr1, r63
.L_case_q:
ld.b r14, 16, r2
blink tr1, r63
.L_case_uq:
ld.ub r14, 16, r2
blink tr1, r63
.L_case_h:
ld.w r14, 16, r2
blink tr1, r63
.L_case_uh:
ld.uw r14, 16, r2
blink tr1, r63
.L_case_v:
add.l r14, r63, r15
ld.l r15, 4, r12
ld.l r15, 8, r14
ld.l r15, 12, r18
addi.l r15, 136, r15
ptabs r18, tr0
blink tr0, r63
.LFE2:
.ffi_closure_SYSV_end:
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
.section ".eh_frame","aw",@progbits
__FRAME_BEGIN__:
.4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
.LSCIE1:
.4byte 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#ifdef PIC
.ascii "zR\0" /* CIE Augmentation */
#else
.byte 0x0 /* CIE Augmentation */
#endif
.uleb128 0x1 /* CIE Code Alignment Factor */
.sleb128 -4 /* CIE Data Alignment Factor */
.byte 0x12 /* CIE RA Column */
#ifdef PIC
.uleb128 0x1 /* Augmentation size */
.byte 0x10 /* FDE Encoding (pcrel) */
#endif
.byte 0xc /* DW_CFA_def_cfa */
.uleb128 0xf
.uleb128 0x0
.align 2
.LECIE1:
.LSFDE1:
.4byte datalabel .LEFDE1-datalabel .LASFDE1 /* FDE Length */
.LASFDE1:
.4byte datalabel .LASFDE1-datalabel __FRAME_BEGIN__
#ifdef PIC
.4byte .LFB1-. /* FDE initial location */
#else
.4byte .LFB1 /* FDE initial location */
#endif
.4byte datalabel .LFE1-datalabel .LFB1 /* FDE address range */
#ifdef PIC
.uleb128 0x0 /* Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte datalabel .LCFI0-datalabel .LFB1
.byte 0xe /* DW_CFA_def_cfa_offset */
.uleb128 0x30
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte datalabel .LCFI1-datalabel .LCFI0
.byte 0x8e /* DW_CFA_offset, column 0xe */
.uleb128 0xc
.byte 0x92 /* DW_CFA_offset, column 0x12 */
.uleb128 0xb
.byte 0x9c /* DW_CFA_offset, column 0x1c */
.uleb128 0xa
.byte 0x9d /* DW_CFA_offset, column 0x1d */
.uleb128 0x8
.byte 0x9e /* DW_CFA_offset, column 0x1e */
.uleb128 0x6
.byte 0x9f /* DW_CFA_offset, column 0x1f */
.uleb128 0x4
.byte 0xa0 /* DW_CFA_offset, column 0x20 */
.uleb128 0x2
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte datalabel .LCFI2-datalabel .LCFI1
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0xe
.align 2
.LEFDE1:
.LSFDE3:
.4byte datalabel .LEFDE3-datalabel .LASFDE3 /* FDE Length */
.LASFDE3:
.4byte datalabel .LASFDE3-datalabel __FRAME_BEGIN__
#ifdef PIC
.4byte .LFB2-. /* FDE initial location */
#else
.4byte .LFB2 /* FDE initial location */
#endif
.4byte datalabel .LFE2-datalabel .LFB2 /* FDE address range */
#ifdef PIC
.uleb128 0x0 /* Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte datalabel .LCFI3-datalabel .LFB2
.byte 0xe /* DW_CFA_def_cfa_offset */
.uleb128 0x88
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte datalabel .LCFI4-datalabel .LCFI3
.byte 0x8c /* DW_CFA_offset, column 0xc */
.uleb128 0x21
.byte 0x8e /* DW_CFA_offset, column 0xe */
.uleb128 0x20
.byte 0x92 /* DW_CFA_offset, column 0x12 */
.uleb128 0x1f
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte datalabel .LCFI5-datalabel .LCFI4
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0xe
.align 2
.LEFDE3:

608
libffi/src/sparc/ffi.c Normal file
View File

@@ -0,0 +1,608 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc.
SPARC 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
void ffi_prep_args_v8(char *stack, extended_cif *ecif)
{
int i;
void **p_argv;
char *argp;
ffi_type **p_arg;
/* Skip 16 words for the window save area */
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 ) */
*(int *) argp = (long)ecif->rvalue;
/* And 1 word for the structure return value. */
argp += sizeof(int);
#ifdef USING_PURIFY
/* Purify will probably complain in our assembly routine, unless we
zero out this memory. */
((int*)argp)[0] = 0;
((int*)argp)[1] = 0;
((int*)argp)[2] = 0;
((int*)argp)[3] = 0;
((int*)argp)[4] = 0;
((int*)argp)[5] = 0;
#endif
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
{
size_t z;
if ((*p_arg)->type == FFI_TYPE_STRUCT
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE
#endif
)
{
*(unsigned int *) argp = (unsigned long)(* p_argv);
z = sizeof(int);
}
else
{
z = (*p_arg)->size;
if (z < sizeof(int))
{
z = sizeof(int);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(signed int *) argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(unsigned int *) argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(signed int *) argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(unsigned int *) argp = *(UINT16 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else
{
memcpy(argp, *p_argv, z);
}
}
p_argv++;
argp += z;
}
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;
argp += sizeof(long long);
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)
{
int wordsize;
if (cif->abi != FFI_V9)
{
wordsize = 4;
/* 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;
}
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 += 16 * wordsize;
/* The stack must be 2 word aligned, so round bytes up
appropriately. */
cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
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_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_layout_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_layout_struct(*ptr, off, ret, intg, flt);
off = ALIGN(off, FFI_SIZEOF_ARG);
break;
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
memmove(ret + off, flt + off, (*ptr)->size);
off += (*ptr)->size;
break;
default:
memmove(ret + off, intg + off, (*ptr)->size);
off += (*ptr)->size;
break;
}
ptr++;
}
return off;
}
#ifdef SPARC64
extern int ffi_call_v9(void *, extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)());
#else
extern int ffi_call_v8(void *, extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)());
#endif
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 */
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:
#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_layout_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;
}
}
#ifdef SPARC64
extern void ffi_closure_v9(void);
#else
extern void ffi_closure_v8(void);
#endif
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
unsigned long fn;
#ifdef SPARC64
/* Trampoline address is equal to the closure address. We take advantage
of that to reduce the trampoline size by 8 bytes. */
FFI_ASSERT (cif->abi == FFI_V9);
fn = (unsigned long) ffi_closure_v9;
tramp[0] = 0x83414000; /* rd %pc, %g1 */
tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
tramp[2] = 0x81c14000; /* jmp %g5 */
tramp[3] = 0x01000000; /* nop */
*((unsigned long *) &tramp[4]) = fn;
#else
unsigned long ctx = (unsigned long) closure;
FFI_ASSERT (cif->abi == FFI_V8);
fn = (unsigned long) ffi_closure_v8;
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
#endif
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* Flush the Icache. FIXME: alignment isn't certain, assume 8 bytes */
#ifdef SPARC64
asm volatile ("flush %0" : : "r" (closure) : "memory");
asm volatile ("flush %0" : : "r" (((char *) closure) + 8) : "memory");
#else
asm volatile ("iflush %0" : : "r" (closure) : "memory");
asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory");
#endif
return FFI_OK;
}
int
ffi_closure_sparc_inner_v8(ffi_closure *closure,
void *rvalue, unsigned long *gpr, unsigned long *scratch)
{
ffi_cif *cif;
ffi_type **arg_types;
void **avalue;
int i, argn;
cif = closure->cif;
arg_types = cif->arg_types;
avalue = alloca(cif->nargs * sizeof(void *));
/* Copy the caller's structure return address so that the closure
returns the data directly to the caller. */
if (cif->flags == FFI_TYPE_STRUCT
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| cif->flags == FFI_TYPE_LONGDOUBLE
#endif
)
rvalue = (void *) gpr[0];
/* Always skip the structure return address. */
argn = 1;
/* Grab the addresses of the arguments from the stack frame. */
for (i = 0; i < cif->nargs; i++)
{
if (arg_types[i]->type == FFI_TYPE_STRUCT
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE
#endif
)
{
/* Straight copy of invisible reference. */
avalue[i] = (void *)gpr[argn++];
}
else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
|| arg_types[i]->type == FFI_TYPE_SINT64
|| arg_types[i]->type == FFI_TYPE_UINT64)
/* gpr is 8-byte aligned. */
&& (argn % 2) != 0)
{
/* Align on a 8-byte boundary. */
scratch[0] = gpr[argn];
scratch[1] = gpr[argn+1];
avalue[i] = scratch;
scratch -= 2;
argn += 2;
}
else
{
/* Always right-justify. */
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
}
}
/* Invoke the closure. */
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_sparc how to perform return type promotions. */
return cif->rtype->type;
}
int
ffi_closure_sparc_inner_v9(ffi_closure *closure,
void *rvalue, unsigned long *gpr, double *fpr)
{
ffi_cif *cif;
ffi_type **arg_types;
void **avalue;
int i, argn, fp_slot_max;
cif = closure->cif;
arg_types = cif->arg_types;
avalue = alloca(cif->nargs * sizeof(void *));
/* Copy the caller's structure return address so that the closure
returns the data directly to the caller. */
if (cif->flags == FFI_TYPE_VOID
&& cif->rtype->type == FFI_TYPE_STRUCT)
{
rvalue = (void *) gpr[0];
/* Skip the structure return address. */
argn = 1;
}
else
argn = 0;
fp_slot_max = 16 - argn;
/* Grab the addresses of the arguments from the stack frame. */
for (i = 0; i < cif->nargs; i++)
{
if (arg_types[i]->type == FFI_TYPE_STRUCT)
{
if (arg_types[i]->size > 16)
{
/* Straight copy of invisible reference. */
avalue[i] = (void *)gpr[argn++];
}
else
{
/* Left-justify. */
ffi_v9_layout_struct(arg_types[i],
0,
(char *) &gpr[argn],
(char *) &gpr[argn],
(char *) &fpr[argn]);
avalue[i] = &gpr[argn];
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
else
{
/* Right-justify. */
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
if (i < fp_slot_max
&& (arg_types[i]->type == FFI_TYPE_FLOAT
|| arg_types[i]->type == FFI_TYPE_DOUBLE
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE
#endif
))
avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
else
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
}
}
/* Invoke the closure. */
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_sparc how to perform return type promotions. */
return cif->rtype->type;
}

View File

@@ -0,0 +1,65 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for SPARC.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- System specific configurations ----------------------------------- */
#if defined(__arch64__) || defined(__sparcv9)
#define SPARC64
#endif
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
FFI_V8,
FFI_V8PLUS,
FFI_V9,
#ifdef SPARC64
FFI_DEFAULT_ABI = FFI_V9,
#else
FFI_DEFAULT_ABI = FFI_V8,
#endif
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
#ifdef SPARC64
#define FFI_TRAMPOLINE_SIZE 24
#else
#define FFI_TRAMPOLINE_SIZE 16
#endif
#endif

267
libffi/src/sparc/v8.S Normal file
View File

@@ -0,0 +1,267 @@
/* -----------------------------------------------------------------------
v8.S - Copyright (c) 1996, 1997, 2003, 2004 Red Hat, Inc.
SPARC 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 <fficonfig.h>
#include <ffi.h>
#define STACKFRAME 96 /* Minimum stack framesize for SPARC */
#define ARGS (64+4) /* Offset of register area in frame */
.text
.align 8
.globl ffi_call_v8
.globl _ffi_call_v8
ffi_call_v8:
_ffi_call_v8:
.LLFB1:
save %sp, -STACKFRAME, %sp
.LLCFI0:
sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
add %sp, STACKFRAME, %l0 ! %l0 has start of
! frame to set up
mov %l0, %o0 ! call routine to set up frame
call %i0
mov %i1, %o1 ! (delay)
ld [%l0+ARGS], %o0 ! call foreign function
ld [%l0+ARGS+4], %o1
ld [%l0+ARGS+8], %o2
ld [%l0+ARGS+12], %o3
ld [%l0+ARGS+16], %o4
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
bz done
nop
cmp %i3, FFI_TYPE_INT
be,a done
st %o0, [%i4] ! (delay)
cmp %i3, FFI_TYPE_FLOAT
be,a done
st %f0, [%i4+0] ! (delay)
cmp %i3, FFI_TYPE_SINT64
be longlong
cmp %i3, FFI_TYPE_DOUBLE
bne done
nop
st %f0, [%i4+0]
st %f1, [%i4+4]
done:
ret
restore
longlong:
st %o0, [%i4+0]
st %o1, [%i4+4]
ret
restore
.LLFE1:
.ffi_call_v8_end:
.size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8
#undef STACKFRAME
#define STACKFRAME 104 /* 16*4 register window +
1*4 struct return +
6*4 args backing store +
3*4 locals */
/* ffi_closure_v8(...)
Receives the closure argument in %g2. */
.text
.align 8
.globl ffi_closure_v8
ffi_closure_v8:
#ifdef HAVE_AS_REGISTER_PSEUDO_OP
.register %g2, #scratch
#endif
.LLFB2:
! Reserve frame space for all arguments in case
! we need to align them on a 8-byte boundary.
ld [%g2+FFI_TRAMPOLINE_SIZE], %g1
ld [%g1+4], %g1
sll %g1, 3, %g1
add %g1, STACKFRAME, %g1
! %g1 == STACKFRAME + 8*nargs
neg %g1
save %sp, %g1, %sp
.LLCFI1:
! Store all of the potential argument registers in va_list format.
st %i0, [%fp+68+0]
st %i1, [%fp+68+4]
st %i2, [%fp+68+8]
st %i3, [%fp+68+12]
st %i4, [%fp+68+16]
st %i5, [%fp+68+20]
! Call ffi_closure_sparc_inner to do the bulk of the work.
mov %g2, %o0
add %fp, -8, %o1
add %fp, 64, %o2
call ffi_closure_sparc_inner_v8
add %fp, -16, %o3
! Load up the return value in the proper type.
! See ffi_prep_cif_machdep for the list of cases.
cmp %o0, FFI_TYPE_VOID
be done1
cmp %o0, FFI_TYPE_INT
be integer
cmp %o0, FFI_TYPE_FLOAT
be,a done1
ld [%fp-8], %f0
cmp %o0, FFI_TYPE_DOUBLE
be,a done1
ldd [%fp-8], %f0
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
cmp %o0, FFI_TYPE_LONGDOUBLE
be done2
#endif
cmp %o0, FFI_TYPE_STRUCT
be done2
! FFI_TYPE_SINT64
! FFI_TYPE_UINT64
ld [%fp-4], %i1
integer:
ld [%fp-8], %i0
done1:
jmp %i7+8
restore
done2:
! Skip 'unimp'.
jmp %i7+12
restore
.LLFE2:
.ffi_closure_v8_end:
.size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8
#ifdef SPARC64
#define WS 8
#define nword xword
#define uanword uaxword
#else
#define WS 4
#define nword long
#define uanword uaword
#endif
#ifdef HAVE_RO_EH_FRAME
.section ".eh_frame",#alloc
#else
.section ".eh_frame",#alloc,#write
#endif
.LLframe1:
.uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
.LLSCIE1:
.uaword 0x0 ! CIE Identifier Tag
.byte 0x1 ! CIE Version
.ascii "zR\0" ! CIE Augmentation
.byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
.byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor
.byte 0xf ! CIE RA Column
.byte 0x1 ! uleb128 0x1; Augmentation size
#ifdef HAVE_AS_SPARC_UA_PCREL
.byte 0x1b ! FDE Encoding (pcrel sdata4)
#else
.byte 0x50 ! FDE Encoding (aligned absolute)
#endif
.byte 0xc ! DW_CFA_def_cfa
.byte 0xe ! uleb128 0xe
.byte 0x0 ! uleb128 0x0
.align WS
.LLECIE1:
.LLSFDE1:
.uaword .LLEFDE1-.LLASFDE1 ! FDE Length
.LLASFDE1:
.uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
#ifdef HAVE_AS_SPARC_UA_PCREL
.uaword %r_disp32(.LLFB1)
.uaword .LLFE1-.LLFB1 ! FDE address range
#else
.align WS
.nword .LLFB1
.uanword .LLFE1-.LLFB1 ! FDE address range
#endif
.byte 0x0 ! uleb128 0x0; Augmentation size
.byte 0x4 ! DW_CFA_advance_loc4
.uaword .LLCFI0-.LLFB1
.byte 0xd ! DW_CFA_def_cfa_register
.byte 0x1e ! uleb128 0x1e
.byte 0x2d ! DW_CFA_GNU_window_save
.byte 0x9 ! DW_CFA_register
.byte 0xf ! uleb128 0xf
.byte 0x1f ! uleb128 0x1f
.align WS
.LLEFDE1:
.LLSFDE2:
.uaword .LLEFDE2-.LLASFDE2 ! FDE Length
.LLASFDE2:
.uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
#ifdef HAVE_AS_SPARC_UA_PCREL
.uaword %r_disp32(.LLFB2)
.uaword .LLFE2-.LLFB2 ! FDE address range
#else
.align WS
.nword .LLFB2
.uanword .LLFE2-.LLFB2 ! FDE address range
#endif
.byte 0x0 ! uleb128 0x0; Augmentation size
.byte 0x4 ! DW_CFA_advance_loc4
.uaword .LLCFI1-.LLFB2
.byte 0xd ! DW_CFA_def_cfa_register
.byte 0x1e ! uleb128 0x1e
.byte 0x2d ! DW_CFA_GNU_window_save
.byte 0x9 ! DW_CFA_register
.byte 0xf ! uleb128 0xf
.byte 0x1f ! uleb128 0x1f
.align WS
.LLEFDE2:

302
libffi/src/sparc/v9.S Normal file
View File

@@ -0,0 +1,302 @@
/* -----------------------------------------------------------------------
v9.S - Copyright (c) 2000, 2003, 2004 Red Hat, Inc.
SPARC 64-bit 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 <fficonfig.h>
#include <ffi.h>
#ifdef SPARC64
/* Only compile this in for 64bit builds, because otherwise the object file
will have inproper architecture due to used instructions. */
#define STACKFRAME 128 /* Minimum stack framesize for SPARC */
#define STACK_BIAS 2047
#define ARGS (128) /* Offset of register area in frame */
.text
.align 8
.globl ffi_call_v9
.globl _ffi_call_v9
ffi_call_v9:
_ffi_call_v9:
.LLFB1:
save %sp, -STACKFRAME, %sp
.LLCFI0:
sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of
! frame to set up
mov %l0, %o0 ! call routine to set up frame
call %i0
mov %i1, %o1 ! (delay)
brz,pt %o0, 1f
ldx [%l0+ARGS], %o0 ! call foreign function
ldd [%l0+ARGS], %f0
ldd [%l0+ARGS+8], %f2
ldd [%l0+ARGS+16], %f4
ldd [%l0+ARGS+24], %f6
ldd [%l0+ARGS+32], %f8
ldd [%l0+ARGS+40], %f10
ldd [%l0+ARGS+48], %f12
ldd [%l0+ARGS+56], %f14
ldd [%l0+ARGS+64], %f16
ldd [%l0+ARGS+72], %f18
ldd [%l0+ARGS+80], %f20
ldd [%l0+ARGS+88], %f22
ldd [%l0+ARGS+96], %f24
ldd [%l0+ARGS+104], %f26
ldd [%l0+ARGS+112], %f28
ldd [%l0+ARGS+120], %f30
1: ldx [%l0+ARGS+8], %o1
ldx [%l0+ARGS+16], %o2
ldx [%l0+ARGS+24], %o3
ldx [%l0+ARGS+32], %o4
ldx [%l0+ARGS+40], %o5
call %i5
sub %l0, STACK_BIAS, %sp ! (delay) switch to frame
! If the return value pointer is NULL, assume no return value.
brz,pn %i4, done
nop
cmp %i3, FFI_TYPE_INT
be,a,pt %icc, done
stx %o0, [%i4+0] ! (delay)
cmp %i3, FFI_TYPE_FLOAT
be,a,pn %icc, done
st %f0, [%i4+0] ! (delay)
cmp %i3, FFI_TYPE_DOUBLE
be,a,pn %icc, done
std %f0, [%i4+0] ! (delay)
cmp %i3, FFI_TYPE_STRUCT
be,pn %icc, dostruct
cmp %i3, FFI_TYPE_LONGDOUBLE
bne,pt %icc, done
nop
std %f0, [%i4+0]
std %f2, [%i4+8]
done: ret
restore
dostruct:
/* This will not work correctly for unions. */
stx %o0, [%i4+0]
stx %o1, [%i4+8]
stx %o2, [%i4+16]
stx %o3, [%i4+24]
std %f0, [%i4+32]
std %f2, [%i4+40]
std %f4, [%i4+48]
std %f6, [%i4+56]
ret
restore
.LLFE1:
.ffi_call_v9_end:
.size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9
#undef STACKFRAME
#define STACKFRAME 336 /* 16*8 register window +
6*8 args backing store +
20*8 locals */
#define FP %fp+STACK_BIAS
/* ffi_closure_v9(...)
Receives the closure argument in %g1. */
.text
.align 8
.globl ffi_closure_v9
ffi_closure_v9:
.LLFB2:
save %sp, -STACKFRAME, %sp
.LLCFI1:
! Store all of the potential argument registers in va_list format.
stx %i0, [FP+128+0]
stx %i1, [FP+128+8]
stx %i2, [FP+128+16]
stx %i3, [FP+128+24]
stx %i4, [FP+128+32]
stx %i5, [FP+128+40]
! Store possible floating point argument registers too.
std %f0, [FP-128]
std %f2, [FP-120]
std %f4, [FP-112]
std %f6, [FP-104]
std %f8, [FP-96]
std %f10, [FP-88]
std %f12, [FP-80]
std %f14, [FP-72]
std %f16, [FP-64]
std %f18, [FP-56]
std %f20, [FP-48]
std %f22, [FP-40]
std %f24, [FP-32]
std %f26, [FP-24]
std %f28, [FP-16]
std %f30, [FP-8]
! Call ffi_closure_sparc_inner to do the bulk of the work.
mov %g1, %o0
add %fp, STACK_BIAS-160, %o1
add %fp, STACK_BIAS+128, %o2
call ffi_closure_sparc_inner_v9
add %fp, STACK_BIAS-128, %o3
! Load up the return value in the proper type.
! See ffi_prep_cif_machdep for the list of cases.
cmp %o0, FFI_TYPE_VOID
be,pn %icc, done1
cmp %o0, FFI_TYPE_INT
be,pn %icc, integer
cmp %o0, FFI_TYPE_FLOAT
be,a,pn %icc, done1
ld [FP-160], %f0
cmp %o0, FFI_TYPE_DOUBLE
be,a,pn %icc, done1
ldd [FP-160], %f0
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
cmp %o0, FFI_TYPE_LONGDOUBLE
be,a,pn %icc, longdouble1
ldd [FP-160], %f0
#endif
! FFI_TYPE_STRUCT
ldx [FP-152], %i1
ldx [FP-144], %i2
ldx [FP-136], %i3
ldd [FP-160], %f0
ldd [FP-152], %f2
ldd [FP-144], %f4
ldd [FP-136], %f6
integer:
ldx [FP-160], %i0
done1:
ret
restore
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
longdouble1:
ldd [FP-152], %f2
ret
restore
#endif
.LLFE2:
.ffi_closure_v9_end:
.size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9
#ifdef HAVE_RO_EH_FRAME
.section ".eh_frame",#alloc
#else
.section ".eh_frame",#alloc,#write
#endif
.LLframe1:
.uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
.LLSCIE1:
.uaword 0x0 ! CIE Identifier Tag
.byte 0x1 ! CIE Version
.ascii "zR\0" ! CIE Augmentation
.byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
.byte 0x78 ! sleb128 -8; CIE Data Alignment Factor
.byte 0xf ! CIE RA Column
.byte 0x1 ! uleb128 0x1; Augmentation size
#ifdef HAVE_AS_SPARC_UA_PCREL
.byte 0x1b ! FDE Encoding (pcrel sdata4)
#else
.byte 0x50 ! FDE Encoding (aligned absolute)
#endif
.byte 0xc ! DW_CFA_def_cfa
.byte 0xe ! uleb128 0xe
.byte 0xff,0xf ! uleb128 0x7ff
.align 8
.LLECIE1:
.LLSFDE1:
.uaword .LLEFDE1-.LLASFDE1 ! FDE Length
.LLASFDE1:
.uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
#ifdef HAVE_AS_SPARC_UA_PCREL
.uaword %r_disp32(.LLFB1)
.uaword .LLFE1-.LLFB1 ! FDE address range
#else
.align 8
.xword .LLFB1
.uaxword .LLFE1-.LLFB1 ! FDE address range
#endif
.byte 0x0 ! uleb128 0x0; Augmentation size
.byte 0x4 ! DW_CFA_advance_loc4
.uaword .LLCFI0-.LLFB1
.byte 0xd ! DW_CFA_def_cfa_register
.byte 0x1e ! uleb128 0x1e
.byte 0x2d ! DW_CFA_GNU_window_save
.byte 0x9 ! DW_CFA_register
.byte 0xf ! uleb128 0xf
.byte 0x1f ! uleb128 0x1f
.align 8
.LLEFDE1:
.LLSFDE2:
.uaword .LLEFDE2-.LLASFDE2 ! FDE Length
.LLASFDE2:
.uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
#ifdef HAVE_AS_SPARC_UA_PCREL
.uaword %r_disp32(.LLFB2)
.uaword .LLFE2-.LLFB2 ! FDE address range
#else
.align 8
.xword .LLFB2
.uaxword .LLFE2-.LLFB2 ! FDE address range
#endif
.byte 0x0 ! uleb128 0x0; Augmentation size
.byte 0x4 ! DW_CFA_advance_loc4
.uaword .LLCFI1-.LLFB2
.byte 0xd ! DW_CFA_def_cfa_register
.byte 0x1e ! uleb128 0x1e
.byte 0x2d ! DW_CFA_GNU_window_save
.byte 0x9 ! DW_CFA_register
.byte 0xf ! uleb128 0xf
.byte 0x1f ! uleb128 0x1f
.align 8
.LLEFDE2:
#endif

60
libffi/src/types.c Normal file
View File

@@ -0,0 +1,60 @@
/* -----------------------------------------------------------------------
types.c - Copyright (c) 1996, 1998 Red Hat, Inc.
Predefined ffi_types needed by libffi.
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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
/* Type definitions */
#define FFI_TYPEDEF(name, type, id) \
struct struct_align_##name { \
char c; \
type x; \
}; \
ffi_type ffi_type_##name = { \
sizeof(type), \
offsetof(struct struct_align_##name, x), \
id, NULL \
}
/* Size and alignment are fake here. They must not be 0. */
ffi_type ffi_type_void = {
1, 1, FFI_TYPE_VOID, NULL
};
FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8);
FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8);
FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16);
FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16);
FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32);
FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32);
FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64);
FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64);
FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER);
FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT);
FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE);
FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE);

403
libffi/src/x86/darwin.S Normal file
View File

@@ -0,0 +1,403 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc.
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.
----------------------------------------------------------------------- */
#ifndef __x86_64__
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.text
.globl _ffi_prep_args
.align 4
.globl _ffi_call_SYSV
_ffi_call_SYSV:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp,%ebp
.LCFI1:
subl $8,%esp
/* 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 */
subl $8,%esp
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
/* Return stack to previous state and call the function */
addl $16,%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 retstruct1b
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
jmp epilogue
retstruct1b:
cmpl $FFI_TYPE_SINT8,%ecx
jne retstruct2b
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
movb %al,0(%ecx)
jmp epilogue
retstruct2b:
cmpl $FFI_TYPE_SINT16,%ecx
jne retstruct
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
movw %ax,0(%ecx)
jmp epilogue
retstruct:
cmpl $FFI_TYPE_STRUCT,%ecx
jne noretval
/* Nothing to do! */
addl $4,%esp
popl %ebp
ret
noretval:
epilogue:
addl $8,%esp
movl %ebp,%esp
popl %ebp
ret
.LFE1:
.ffi_call_SYSV_end:
.align 4
FFI_HIDDEN (ffi_closure_SYSV)
.globl _ffi_closure_SYSV
_ffi_closure_SYSV:
.LFB2:
pushl %ebp
.LCFI2:
movl %esp, %ebp
.LCFI3:
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp) /* resp */
leal 8(%ebp), %edx
movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
leal -12(%ebp), %edx
movl %edx, (%esp) /* &resp */
movl %ebx, 8(%esp)
.LCFI7:
call L_ffi_closure_SYSV_inner$stub
movl 8(%esp), %ebx
movl -12(%ebp), %ecx
cmpl $FFI_TYPE_INT, %eax
je .Lcls_retint
cmpl $FFI_TYPE_FLOAT, %eax
je .Lcls_retfloat
cmpl $FFI_TYPE_DOUBLE, %eax
je .Lcls_retdouble
cmpl $FFI_TYPE_LONGDOUBLE, %eax
je .Lcls_retldouble
cmpl $FFI_TYPE_SINT64, %eax
je .Lcls_retllong
cmpl $FFI_TYPE_SINT8, %eax
je .Lcls_retstruct1
cmpl $FFI_TYPE_SINT16, %eax
je .Lcls_retstruct2
cmpl $FFI_TYPE_STRUCT, %eax
je .Lcls_retstruct
.Lcls_epilogue:
movl %ebp, %esp
popl %ebp
ret
.Lcls_retint:
movl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retfloat:
flds (%ecx)
jmp .Lcls_epilogue
.Lcls_retdouble:
fldl (%ecx)
jmp .Lcls_epilogue
.Lcls_retldouble:
fldt (%ecx)
jmp .Lcls_epilogue
.Lcls_retllong:
movl (%ecx), %eax
movl 4(%ecx), %edx
jmp .Lcls_epilogue
.Lcls_retstruct1:
movsbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct2:
movswl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct:
lea -8(%ebp),%esp
movl %ebp, %esp
popl %ebp
ret $4
.LFE2:
#if !FFI_NO_RAW_API
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
#define CIF_FLAGS_OFFSET 20
.align 4
FFI_HIDDEN (ffi_closure_raw_SYSV)
.globl _ffi_closure_raw_SYSV
_ffi_closure_raw_SYSV:
.LFB3:
pushl %ebp
.LCFI4:
movl %esp, %ebp
.LCFI5:
pushl %esi
.LCFI6:
subl $36, %esp
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
movl %edx, 12(%esp) /* user_data */
leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
movl %edx, 8(%esp) /* raw_args */
leal -24(%ebp), %edx
movl %edx, 4(%esp) /* &res */
movl %esi, (%esp) /* cif */
call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
cmpl $FFI_TYPE_INT, %eax
je .Lrcls_retint
cmpl $FFI_TYPE_FLOAT, %eax
je .Lrcls_retfloat
cmpl $FFI_TYPE_DOUBLE, %eax
je .Lrcls_retdouble
cmpl $FFI_TYPE_LONGDOUBLE, %eax
je .Lrcls_retldouble
cmpl $FFI_TYPE_SINT64, %eax
je .Lrcls_retllong
.Lrcls_epilogue:
addl $36, %esp
popl %esi
popl %ebp
ret
.Lrcls_retint:
movl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retfloat:
flds -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retdouble:
fldl -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retldouble:
fldt -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retllong:
movl -24(%ebp), %eax
movl -20(%ebp), %edx
jmp .Lrcls_epilogue
.LFE3:
#endif
.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_ffi_closure_SYSV_inner$stub:
.indirect_symbol _ffi_closure_SYSV_inner
hlt ; hlt ; hlt ; hlt ; hlt
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0
LSCIE1:
.long 0x0
.byte 0x1
.ascii "zR\0"
.byte 0x1
.byte 0x7c
.byte 0x8
.byte 0x1
.byte 0x10
.byte 0xc
.byte 0x5
.byte 0x4
.byte 0x88
.byte 0x1
.align 2
LECIE1:
.globl _ffi_call_SYSV.eh
_ffi_call_SYSV.eh:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1
.long L$set$1
LASFDE1:
.long LASFDE1-EH_frame1
.long .LFB1-.
.set L$set$2,.LFE1-.LFB1
.long L$set$2
.byte 0x0
.byte 0x4
.set L$set$3,.LCFI0-.LFB1
.long L$set$3
.byte 0xe
.byte 0x8
.byte 0x84
.byte 0x2
.byte 0x4
.set L$set$4,.LCFI1-.LCFI0
.long L$set$4
.byte 0xd
.byte 0x4
.align 2
LEFDE1:
.globl _ffi_closure_SYSV.eh
_ffi_closure_SYSV.eh:
LSFDE2:
.set L$set$5,LEFDE2-LASFDE2
.long L$set$5
LASFDE2:
.long LASFDE2-EH_frame1
.long .LFB2-.
.set L$set$6,.LFE2-.LFB2
.long L$set$6
.byte 0x0
.byte 0x4
.set L$set$7,.LCFI2-.LFB2
.long L$set$7
.byte 0xe
.byte 0x8
.byte 0x84
.byte 0x2
.byte 0x4
.set L$set$8,.LCFI3-.LCFI2
.long L$set$8
.byte 0xd
.byte 0x4
.align 2
LEFDE2:
#if !FFI_NO_RAW_API
.globl _ffi_closure_raw_SYSV.eh
_ffi_closure_raw_SYSV.eh:
LSFDE3:
.set L$set$10,LEFDE3-LASFDE3
.long L$set$10
LASFDE3:
.long LASFDE3-EH_frame1
.long .LFB3-.
.set L$set$11,.LFE3-.LFB3
.long L$set$11
.byte 0x0
.byte 0x4
.set L$set$12,.LCFI4-.LFB3
.long L$set$12
.byte 0xe
.byte 0x8
.byte 0x84
.byte 0x2
.byte 0x4
.set L$set$13,.LCFI5-.LCFI4
.long L$set$13
.byte 0xd
.byte 0x4
.byte 0x4
.set L$set$14,.LCFI6-.LCFI5
.long L$set$14
.byte 0x85
.byte 0x3
.align 2
LEFDE3:
#endif
#endif /* ifndef __x86_64__ */

415
libffi/src/x86/darwin64.S Normal file
View File

@@ -0,0 +1,415 @@
/* -----------------------------------------------------------------------
darwin64.S - Copyright (c) 2006 Free Software Foundation, Inc.
derived from unix64.S
x86-64 Foreign Function Interface for Darwin.
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.
----------------------------------------------------------------------- */
#ifdef __x86_64__
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.file "darwin64.S"
.text
/* ffi_call_unix64 (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_unix64
_ffi_call_unix64:
LUW0:
movq (%rsp), %r10 /* Load return address. */
leaq (%rdi, %rsi), %rax /* Find local stack base. */
movq %rdx, (%rax) /* Save flags. */
movq %rcx, 8(%rax) /* Save raddr. */
movq %rbp, 16(%rax) /* Save old frame pointer. */
movq %r10, 24(%rax) /* Relocate return address. */
movq %rax, %rbp /* Finalize local stack frame. */
LUW1:
movq %rdi, %r10 /* Save a copy of the register area. */
movq %r8, %r11 /* Save a copy of the target fn. */
movl %r9d, %eax /* Set number of SSE registers. */
/* Load up all argument registers. */
movq (%r10), %rdi
movq 8(%r10), %rsi
movq 16(%r10), %rdx
movq 24(%r10), %rcx
movq 32(%r10), %r8
movq 40(%r10), %r9
testl %eax, %eax
jnz Lload_sse
Lret_from_load_sse:
/* Deallocate the reg arg area. */
leaq 176(%r10), %rsp
/* Call the user function. */
call *%r11
/* Deallocate stack arg area; local stack frame in redzone. */
leaq 24(%rbp), %rsp
movq 0(%rbp), %rcx /* Reload flags. */
movq 8(%rbp), %rdi /* Reload raddr. */
movq 16(%rbp), %rbp /* Reload old frame pointer. */
LUW2:
/* The first byte of the flags contains the FFI_TYPE. */
movzbl %cl, %r10d
leaq Lstore_table(%rip), %r11
movslq (%r11, %r10, 4), %r10
addq %r11, %r10
jmp *%r10
Lstore_table:
.long Lst_void-Lstore_table /* FFI_TYPE_VOID */
.long Lst_sint32-Lstore_table /* FFI_TYPE_INT */
.long Lst_float-Lstore_table /* FFI_TYPE_FLOAT */
.long Lst_double-Lstore_table /* FFI_TYPE_DOUBLE */
.long Lst_ldouble-Lstore_table /* FFI_TYPE_LONGDOUBLE */
.long Lst_uint8-Lstore_table /* FFI_TYPE_UINT8 */
.long Lst_sint8-Lstore_table /* FFI_TYPE_SINT8 */
.long Lst_uint16-Lstore_table /* FFI_TYPE_UINT16 */
.long Lst_sint16-Lstore_table /* FFI_TYPE_SINT16 */
.long Lst_uint32-Lstore_table /* FFI_TYPE_UINT32 */
.long Lst_sint32-Lstore_table /* FFI_TYPE_SINT32 */
.long Lst_int64-Lstore_table /* FFI_TYPE_UINT64 */
.long Lst_int64-Lstore_table /* FFI_TYPE_SINT64 */
.long Lst_struct-Lstore_table /* FFI_TYPE_STRUCT */
.long Lst_int64-Lstore_table /* FFI_TYPE_POINTER */
.text
.align 3
Lst_void:
ret
.align 3
Lst_uint8:
movzbq %al, %rax
movq %rax, (%rdi)
ret
.align 3
Lst_sint8:
movsbq %al, %rax
movq %rax, (%rdi)
ret
.align 3
Lst_uint16:
movzwq %ax, %rax
movq %rax, (%rdi)
.align 3
Lst_sint16:
movswq %ax, %rax
movq %rax, (%rdi)
ret
.align 3
Lst_uint32:
movl %eax, %eax
movq %rax, (%rdi)
.align 3
Lst_sint32:
cltq
movq %rax, (%rdi)
ret
.align 3
Lst_int64:
movq %rax, (%rdi)
ret
.align 3
Lst_float:
movss %xmm0, (%rdi)
ret
.align 3
Lst_double:
movsd %xmm0, (%rdi)
ret
Lst_ldouble:
fstpt (%rdi)
ret
.align 3
Lst_struct:
leaq -20(%rsp), %rsi /* Scratch area in redzone. */
/* We have to locate the values now, and since we don't want to
write too much data into the user's return value, we spill the
value to a 16 byte scratch area first. Bits 8, 9, and 10
control where the values are located. Only one of the three
bits will be set; see ffi_prep_cif_machdep for the pattern. */
movd %xmm0, %r10
movd %xmm1, %r11
testl $0x100, %ecx
cmovnz %rax, %rdx
cmovnz %r10, %rax
testl $0x200, %ecx
cmovnz %r10, %rdx
testl $0x400, %ecx
cmovnz %r10, %rax
cmovnz %r11, %rdx
movq %rax, (%rsi)
movq %rdx, 8(%rsi)
/* Bits 12-31 contain the true size of the structure. Copy from
the scratch area to the true destination. */
shrl $12, %ecx
rep movsb
ret
/* Many times we can avoid loading any SSE registers at all.
It's not worth an indirect jump to load the exact set of
SSE registers needed; zero or all is a good compromise. */
.align 3
LUW3:
Lload_sse:
movdqa 48(%r10), %xmm0
movdqa 64(%r10), %xmm1
movdqa 80(%r10), %xmm2
movdqa 96(%r10), %xmm3
movdqa 112(%r10), %xmm4
movdqa 128(%r10), %xmm5
movdqa 144(%r10), %xmm6
movdqa 160(%r10), %xmm7
jmp Lret_from_load_sse
LUW4:
.align 3
.globl _ffi_closure_unix64
_ffi_closure_unix64:
LUW5:
/* The carry flag is set by the trampoline iff SSE registers
are used. Don't clobber it before the branch instruction. */
leaq -200(%rsp), %rsp
LUW6:
movq %rdi, (%rsp)
movq %rsi, 8(%rsp)
movq %rdx, 16(%rsp)
movq %rcx, 24(%rsp)
movq %r8, 32(%rsp)
movq %r9, 40(%rsp)
jc Lsave_sse
Lret_from_save_sse:
movq %r10, %rdi
leaq 176(%rsp), %rsi
movq %rsp, %rdx
leaq 208(%rsp), %rcx
call _ffi_closure_unix64_inner
/* Deallocate stack frame early; return value is now in redzone. */
addq $200, %rsp
LUW7:
/* The first byte of the return value contains the FFI_TYPE. */
movzbl %al, %r10d
leaq Lload_table(%rip), %r11
movslq (%r11, %r10, 4), %r10
addq %r11, %r10
jmp *%r10
Lload_table:
.long Lld_void-Lload_table /* FFI_TYPE_VOID */
.long Lld_int32-Lload_table /* FFI_TYPE_INT */
.long Lld_float-Lload_table /* FFI_TYPE_FLOAT */
.long Lld_double-Lload_table /* FFI_TYPE_DOUBLE */
.long Lld_ldouble-Lload_table /* FFI_TYPE_LONGDOUBLE */
.long Lld_int8-Lload_table /* FFI_TYPE_UINT8 */
.long Lld_int8-Lload_table /* FFI_TYPE_SINT8 */
.long Lld_int16-Lload_table /* FFI_TYPE_UINT16 */
.long Lld_int16-Lload_table /* FFI_TYPE_SINT16 */
.long Lld_int32-Lload_table /* FFI_TYPE_UINT32 */
.long Lld_int32-Lload_table /* FFI_TYPE_SINT32 */
.long Lld_int64-Lload_table /* FFI_TYPE_UINT64 */
.long Lld_int64-Lload_table /* FFI_TYPE_SINT64 */
.long Lld_struct-Lload_table /* FFI_TYPE_STRUCT */
.long Lld_int64-Lload_table /* FFI_TYPE_POINTER */
.text
.align 3
Lld_void:
ret
.align 3
Lld_int8:
movzbl -24(%rsp), %eax
ret
.align 3
Lld_int16:
movzwl -24(%rsp), %eax
ret
.align 3
Lld_int32:
movl -24(%rsp), %eax
ret
.align 3
Lld_int64:
movq -24(%rsp), %rax
ret
.align 3
Lld_float:
movss -24(%rsp), %xmm0
ret
.align 3
Lld_double:
movsd -24(%rsp), %xmm0
ret
.align 3
Lld_ldouble:
fldt -24(%rsp)
ret
.align 3
Lld_struct:
/* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
%rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading
both rdx and xmm1 with the second word. For the remaining,
bit 8 set means xmm0 gets the second word, and bit 9 means
that rax gets the second word. */
movq -24(%rsp), %rcx
movq -16(%rsp), %rdx
movq -16(%rsp), %xmm1
testl $0x100, %eax
cmovnz %rdx, %rcx
movd %rcx, %xmm0
testl $0x200, %eax
movq -24(%rsp), %rax
cmovnz %rdx, %rax
ret
/* See the comment above Lload_sse; the same logic applies here. */
.align 3
LUW8:
Lsave_sse:
movdqa %xmm0, 48(%rsp)
movdqa %xmm1, 64(%rsp)
movdqa %xmm2, 80(%rsp)
movdqa %xmm3, 96(%rsp)
movdqa %xmm4, 112(%rsp)
movdqa %xmm5, 128(%rsp)
movdqa %xmm6, 144(%rsp)
movdqa %xmm7, 160(%rsp)
jmp Lret_from_save_sse
LUW9:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1 /* CIE Length */
.long L$set$0
LSCIE1:
.long 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
.ascii "zR\0" /* CIE Augmentation */
.byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
.byte 0x78 /* sleb128 -8; CIE Data Alignment Factor */
.byte 0x10 /* CIE RA Column */
.byte 0x1 /* uleb128 0x1; Augmentation size */
.byte 0x10 /* FDE Encoding (pcrel sdata4) */
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
.byte 0x7 /* uleb128 0x7 */
.byte 0x8 /* uleb128 0x8 */
.byte 0x90 /* DW_CFA_offset, column 0x10 */
.byte 0x1
.align 3
LECIE1:
.globl _ffi_call_unix64.eh
_ffi_call_unix64.eh:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1 /* FDE Length */
.long L$set$1
LASFDE1:
.long LASFDE1-EH_frame1 /* FDE CIE offset */
.quad LUW0-. /* FDE initial location */
.set L$set$2,LUW4-LUW0 /* FDE address range */
.quad L$set$2
.byte 0x0 /* Augmentation size */
.byte 0x4 /* DW_CFA_advance_loc4 */
.set L$set$3,LUW1-LUW0
.long L$set$3
/* New stack frame based off rbp. This is a itty bit of unwind
trickery in that the CFA *has* changed. There is no easy way
to describe it correctly on entry to the function. Fortunately,
it doesn't matter too much since at all points we can correctly
unwind back to ffi_call. Note that the location to which we
moved the return address is (the new) CFA-8, so from the
perspective of the unwind info, it hasn't moved. */
.byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */
.byte 0x6
.byte 0x20
.byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */
.byte 0x2
.byte 0xa /* DW_CFA_remember_state */
.byte 0x4 /* DW_CFA_advance_loc4 */
.set L$set$4,LUW2-LUW1
.long L$set$4
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
.byte 0x7
.byte 0x8
.byte 0xc0+6 /* DW_CFA_restore, %rbp */
.byte 0x4 /* DW_CFA_advance_loc4 */
.set L$set$5,LUW3-LUW2
.long L$set$5
.byte 0xb /* DW_CFA_restore_state */
.align 3
LEFDE1:
.globl _ffi_closure_unix64.eh
_ffi_closure_unix64.eh:
LSFDE3:
.set L$set$6,LEFDE3-LASFDE3 /* FDE Length */
.long L$set$6
LASFDE3:
.long LASFDE3-EH_frame1 /* FDE CIE offset */
.quad LUW5-. /* FDE initial location */
.set L$set$7,LUW9-LUW5 /* FDE address range */
.quad L$set$7
.byte 0x0 /* Augmentation size */
.byte 0x4 /* DW_CFA_advance_loc4 */
.set L$set$8,LUW6-LUW5
.long L$set$8
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 208,1 /* uleb128 208 */
.byte 0xa /* DW_CFA_remember_state */
.byte 0x4 /* DW_CFA_advance_loc4 */
.set L$set$9,LUW7-LUW6
.long L$set$9
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x8
.byte 0x4 /* DW_CFA_advance_loc4 */
.set L$set$10,LUW8-LUW7
.long L$set$10
.byte 0xb /* DW_CFA_restore_state */
.align 3
LEFDE3:
.subsections_via_symbols
#endif /* __x86_64__ */

432
libffi/src/x86/ffi.c Normal file
View File

@@ -0,0 +1,432 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2002 Bo Thorsen
Copyright (c) 2002 Roger Sayle
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.
----------------------------------------------------------------------- */
#ifndef __x86_64__
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* 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)
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if (ecif->cif->flags == FFI_TYPE_STRUCT)
{
*(void **) argp = ecif->rvalue;
argp += 4;
}
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
i != 0;
i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(int) - 1) & (unsigned) argp)
argp = (char *) ALIGN(argp, sizeof(int));
z = (*p_arg)->size;
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);
break;
case FFI_TYPE_SINT32:
*(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
case FFI_TYPE_STRUCT:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else
{
memcpy(argp, *p_argv, z);
}
p_argv++;
argp += z;
}
return;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
#ifdef X86
case FFI_TYPE_STRUCT:
#endif
case FFI_TYPE_SINT64:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_UINT64:
cif->flags = FFI_TYPE_SINT64;
break;
#ifndef X86
case FFI_TYPE_STRUCT:
if (cif->rtype->size == 1)
{
cif->flags = FFI_TYPE_SINT8; /* same as char size */
}
else if (cif->rtype->size == 2)
{
cif->flags = FFI_TYPE_SINT16; /* same as short size */
}
else if (cif->rtype->size == 4)
{
cif->flags = FFI_TYPE_INT; /* same as int type */
}
else if (cif->rtype->size == 8)
{
cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
}
else
{
cif->flags = FFI_TYPE_STRUCT;
}
break;
#endif
default:
cif->flags = FFI_TYPE_INT;
break;
}
#ifdef X86_DARWIN
cif->bytes = (cif->bytes + 15) & ~0xF;
#endif
return FFI_OK;
}
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)());
#ifdef X86_WIN32
extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)());
#endif /* X86_WIN32 */
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->flags == 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;
#ifdef X86_WIN32
case FFI_STDCALL:
ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
#endif /* X86_WIN32 */
default:
FFI_ASSERT(0);
break;
}
}
/** private members **/
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
void** args, ffi_cif* cif);
void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
__attribute__ ((regparm(1)));
unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
__attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
__attribute__ ((regparm(1)));
/* This function is jumped to by the trampoline */
unsigned int FFI_HIDDEN
ffi_closure_SYSV_inner (closure, respp, args)
ffi_closure *closure;
void **respp;
void *args;
{
// our various things...
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);
(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)
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if ( cif->flags == FFI_TYPE_STRUCT ) {
*rvalue = *(void **) argp;
argp += 4;
}
p_argv = avalue;
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(int) - 1) & (unsigned) argp) {
argp = (char *) ALIGN(argp, sizeof(int));
}
z = (*p_arg)->size;
/* because we're little endian, this is what it turns into. */
*p_argv = (void*) argp;
p_argv++;
argp += z;
}
return;
}
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
unsigned int __fun = (unsigned int)(FUN); \
unsigned int __ctx = (unsigned int)(CTX); \
unsigned int __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \
*(unsigned char*) &__tramp[0] = 0xb8; \
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
*(unsigned char *) &__tramp[5] = 0xe9; \
*(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
})
/* the cif must already be prep'ed */
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
FFI_ASSERT (cif->abi == FFI_SYSV);
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
&ffi_closure_SYSV, \
(void*)closure);
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
/* ------- Native raw API support -------------------------------- */
#if !FFI_NO_RAW_API
ffi_status
ffi_prep_raw_closure (ffi_raw_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
{
int i;
FFI_ASSERT (cif->abi == FFI_SYSV);
// we currently don't support certain kinds of arguments for raw
// closures. This should be implemented by a separate assembly language
// routine, since it would require argument processing, something we
// don't do now for performance.
for (i = cif->nargs-1; i >= 0; i--)
{
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
}
FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
(void*)closure);
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
static void
ffi_prep_args_raw(char *stack, extended_cif *ecif)
{
memcpy (stack, ecif->avalue, ecif->cif->bytes);
}
/* we borrow this routine from libffi (it must be changed, though, to
* actually call the function passed in the first argument. as of
* libffi-1.20, this is not the case.)
*/
extern void
ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)());
#ifdef X86_WIN32
extern void
ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)());
#endif /* X86_WIN32 */
void
ffi_raw_call(ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *fake_avalue)
{
extended_cif ecif;
void **avalue = (void **)fake_avalue;
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_raw, &ecif, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
#ifdef X86_WIN32
case FFI_STDCALL:
ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
#endif /* X86_WIN32 */
default:
FFI_ASSERT(0);
break;
}
}
#endif
#endif /* __x86_64__ */

569
libffi/src/x86/ffi64.c Normal file
View File

@@ -0,0 +1,569 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
x86-64 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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <stdarg.h>
#ifdef __x86_64__
#define MAX_GPR_REGS 6
#define MAX_SSE_REGS 8
struct register_args
{
/* Registers for argument passing. */
UINT64 gpr[MAX_GPR_REGS];
__int128_t sse[MAX_SSE_REGS];
};
extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
void *raddr, void (*fnaddr)(), unsigned ssecount);
/* All reference to register classes here is identical to the code in
gcc/config/i386/i386.c. Do *not* change one without the other. */
/* Register class used for passing given 64bit part of the argument.
These represent classes as documented by the PS ABI, with the exception
of SSESF, SSEDF classes, that are basically SSE class, just gcc will
use SF or DFmode move instead of DImode to avoid reformating penalties.
Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
whenever possible (upper half does contain padding). */
enum x86_64_reg_class
{
X86_64_NO_CLASS,
X86_64_INTEGER_CLASS,
X86_64_INTEGERSI_CLASS,
X86_64_SSE_CLASS,
X86_64_SSESF_CLASS,
X86_64_SSEDF_CLASS,
X86_64_SSEUP_CLASS,
X86_64_X87_CLASS,
X86_64_X87UP_CLASS,
X86_64_COMPLEX_X87_CLASS,
X86_64_MEMORY_CLASS
};
#define MAX_CLASSES 4
#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
of this code is to classify each 8bytes of incoming argument by the register
class and assign registers accordingly. */
/* Return the union class of CLASS1 and CLASS2.
See the x86-64 PS ABI for details. */
static enum x86_64_reg_class
merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
{
/* Rule #1: If both classes are equal, this is the resulting class. */
if (class1 == class2)
return class1;
/* Rule #2: If one of the classes is NO_CLASS, the resulting class is
the other class. */
if (class1 == X86_64_NO_CLASS)
return class2;
if (class2 == X86_64_NO_CLASS)
return class1;
/* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
return X86_64_MEMORY_CLASS;
/* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
|| (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
return X86_64_INTEGERSI_CLASS;
if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
|| class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
return X86_64_INTEGER_CLASS;
/* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
MEMORY is used. */
if (class1 == X86_64_X87_CLASS
|| class1 == X86_64_X87UP_CLASS
|| class1 == X86_64_COMPLEX_X87_CLASS
|| class2 == X86_64_X87_CLASS
|| class2 == X86_64_X87UP_CLASS
|| class2 == X86_64_COMPLEX_X87_CLASS)
return X86_64_MEMORY_CLASS;
/* Rule #6: Otherwise class SSE is used. */
return X86_64_SSE_CLASS;
}
/* Classify the argument of type TYPE and mode MODE.
CLASSES will be filled by the register class used to pass each word
of the operand. The number of words is returned. In case the parameter
should be passed in memory, 0 is returned. As a special case for zero
sized containers, classes[0] will be NO_CLASS and 1 is returned.
See the x86-64 PS ABI for details.
*/
static int
classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
size_t byte_offset)
{
switch (type->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_POINTER:
if (byte_offset + type->size <= 4)
classes[0] = X86_64_INTEGERSI_CLASS;
else
classes[0] = X86_64_INTEGER_CLASS;
return 1;
case FFI_TYPE_FLOAT:
if (byte_offset == 0)
classes[0] = X86_64_SSESF_CLASS;
else
classes[0] = X86_64_SSE_CLASS;
return 1;
case FFI_TYPE_DOUBLE:
classes[0] = X86_64_SSEDF_CLASS;
return 1;
case FFI_TYPE_LONGDOUBLE:
classes[0] = X86_64_X87_CLASS;
classes[1] = X86_64_X87UP_CLASS;
return 2;
case FFI_TYPE_STRUCT:
{
const int UNITS_PER_WORD = 8;
int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
ffi_type **ptr;
int i;
enum x86_64_reg_class subclasses[MAX_CLASSES];
/* If the struct is larger than 16 bytes, pass it on the stack. */
if (type->size > 16)
return 0;
for (i = 0; i < words; i++)
classes[i] = X86_64_NO_CLASS;
/* Merge the fields of structure. */
for (ptr = type->elements; *ptr != NULL; ptr++)
{
int num;
byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
num = classify_argument (*ptr, subclasses, byte_offset % 8);
if (num == 0)
return 0;
for (i = 0; i < num; i++)
{
int pos = byte_offset / 8;
classes[i + pos] =
merge_classes (subclasses[i], classes[i + pos]);
}
byte_offset += (*ptr)->size;
}
/* Final merger cleanup. */
for (i = 0; i < words; i++)
{
/* If one class is MEMORY, everything should be passed in
memory. */
if (classes[i] == X86_64_MEMORY_CLASS)
return 0;
/* The X86_64_SSEUP_CLASS should be always preceded by
X86_64_SSE_CLASS. */
if (classes[i] == X86_64_SSEUP_CLASS
&& (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
classes[i] = X86_64_SSE_CLASS;
/* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */
if (classes[i] == X86_64_X87UP_CLASS
&& (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
classes[i] = X86_64_SSE_CLASS;
}
return words;
}
default:
FFI_ASSERT(0);
}
return 0; /* Never reached. */
}
/* Examine the argument and return set number of register required in each
class. Return zero iff parameter should be passed in memory, otherwise
the number of registers. */
static int
examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
_Bool in_return, int *pngpr, int *pnsse)
{
int i, n, ngpr, nsse;
n = classify_argument (type, classes, 0);
if (n == 0)
return 0;
ngpr = nsse = 0;
for (i = 0; i < n; ++i)
switch (classes[i])
{
case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS:
ngpr++;
break;
case X86_64_SSE_CLASS:
case X86_64_SSESF_CLASS:
case X86_64_SSEDF_CLASS:
nsse++;
break;
case X86_64_NO_CLASS:
case X86_64_SSEUP_CLASS:
break;
case X86_64_X87_CLASS:
case X86_64_X87UP_CLASS:
case X86_64_COMPLEX_X87_CLASS:
return in_return != 0;
default:
abort ();
}
*pngpr = ngpr;
*pnsse = nsse;
return n;
}
/* Perform machine dependent cif processing. */
ffi_status
ffi_prep_cif_machdep (ffi_cif *cif)
{
int gprcount, ssecount, i, avn, n, ngpr, nsse, flags;
enum x86_64_reg_class classes[MAX_CLASSES];
size_t bytes;
gprcount = ssecount = 0;
flags = cif->rtype->type;
if (flags != FFI_TYPE_VOID)
{
n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
if (n == 0)
{
/* The return value is passed in memory. A pointer to that
memory is the first argument. Allocate a register for it. */
gprcount++;
/* We don't have to do anything in asm for the return. */
flags = FFI_TYPE_VOID;
}
else if (flags == FFI_TYPE_STRUCT)
{
/* Mark which registers the result appears in. */
_Bool sse0 = SSE_CLASS_P (classes[0]);
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
if (sse0 && !sse1)
flags |= 1 << 8;
else if (!sse0 && sse1)
flags |= 1 << 9;
else if (sse0 && sse1)
flags |= 1 << 10;
/* Mark the true size of the structure. */
flags |= cif->rtype->size << 12;
}
}
/* Go over all arguments and determine the way they should be passed.
If it's in a register and there is space for it, let that be so. If
not, add it's size to the stack byte count. */
for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
{
if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{
long align = cif->arg_types[i]->alignment;
if (align < 8)
align = 8;
bytes = ALIGN(bytes, align);
bytes += cif->arg_types[i]->size;
}
else
{
gprcount += ngpr;
ssecount += nsse;
}
}
if (ssecount)
flags |= 1 << 11;
cif->flags = flags;
cif->bytes = bytes;
return FFI_OK;
}
void
ffi_call (ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{
enum x86_64_reg_class classes[MAX_CLASSES];
char *stack, *argp;
ffi_type **arg_types;
int gprcount, ssecount, ngpr, nsse, i, avn;
_Bool ret_in_memory;
struct register_args *reg_args;
/* Can't call 32-bit mode from 64-bit mode. */
FFI_ASSERT (cif->abi == FFI_UNIX64);
/* If the return value is a struct and we don't have a return value
address then we need to make one. Note the setting of flags to
VOID above in ffi_prep_cif_machdep. */
ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
&& (cif->flags & 0xff) == FFI_TYPE_VOID);
if (rvalue == NULL && ret_in_memory)
rvalue = alloca (cif->rtype->size);
/* Allocate the space for the arguments, plus 4 words of temp space. */
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
reg_args = (struct register_args *) stack;
argp = stack + sizeof (struct register_args);
gprcount = ssecount = 0;
/* If the return value is passed in memory, add the pointer as the
first integer argument. */
if (ret_in_memory)
reg_args->gpr[gprcount++] = (long) rvalue;
avn = cif->nargs;
arg_types = cif->arg_types;
for (i = 0; i < avn; ++i)
{
size_t size = arg_types[i]->size;
int n;
n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
if (n == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{
long align = arg_types[i]->alignment;
/* Stack arguments are *always* at least 8 byte aligned. */
if (align < 8)
align = 8;
/* Pass this argument in memory. */
argp = (void *) ALIGN (argp, align);
memcpy (argp, avalue[i], size);
argp += size;
}
else
{
/* The argument is passed entirely in registers. */
char *a = (char *) avalue[i];
int j;
for (j = 0; j < n; j++, a += 8, size -= 8)
{
switch (classes[j])
{
case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS:
reg_args->gpr[gprcount] = 0;
memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
gprcount++;
break;
case X86_64_SSE_CLASS:
case X86_64_SSEDF_CLASS:
reg_args->sse[ssecount++] = *(UINT64 *) a;
break;
case X86_64_SSESF_CLASS:
reg_args->sse[ssecount++] = *(UINT32 *) a;
break;
default:
abort();
}
}
}
}
ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
cif->flags, rvalue, fn, ssecount);
}
extern void ffi_closure_unix64(void);
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
volatile unsigned short *tramp;
tramp = (volatile unsigned short *) &closure->tramp[0];
tramp[0] = 0xbb49; /* mov <code>, %r11 */
*(void * volatile *) &tramp[1] = ffi_closure_unix64;
tramp[5] = 0xba49; /* mov <data>, %r10 */
*(void * volatile *) &tramp[6] = closure;
/* Set the carry bit iff the function uses any sse registers.
This is clc or stc, together with the first byte of the jmp. */
tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
tramp[11] = 0xe3ff; /* jmp *%r11 */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
return FFI_OK;
}
int
ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
struct register_args *reg_args, char *argp)
{
ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
long i, avn;
int gprcount, ssecount, ngpr, nsse;
int ret;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
gprcount = ssecount = 0;
ret = cif->rtype->type;
if (ret != FFI_TYPE_VOID)
{
enum x86_64_reg_class classes[MAX_CLASSES];
int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
if (n == 0)
{
/* The return value goes in memory. Arrange for the closure
return value to go directly back to the original caller. */
rvalue = (void *) reg_args->gpr[gprcount++];
/* We don't have to do anything in asm for the return. */
ret = FFI_TYPE_VOID;
}
else if (ret == FFI_TYPE_STRUCT && n == 2)
{
/* Mark which register the second word of the structure goes in. */
_Bool sse0 = SSE_CLASS_P (classes[0]);
_Bool sse1 = SSE_CLASS_P (classes[1]);
if (!sse0 && sse1)
ret |= 1 << 8;
else if (sse0 && !sse1)
ret |= 1 << 9;
}
}
avn = cif->nargs;
arg_types = cif->arg_types;
for (i = 0; i < avn; ++i)
{
enum x86_64_reg_class classes[MAX_CLASSES];
int n;
n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
if (n == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{
long align = arg_types[i]->alignment;
/* Stack arguments are *always* at least 8 byte aligned. */
if (align < 8)
align = 8;
/* Pass this argument in memory. */
argp = (void *) ALIGN (argp, align);
avalue[i] = argp;
argp += arg_types[i]->size;
}
/* If the argument is in a single register, or two consecutive
registers, then we can use that address directly. */
else if (n == 1
|| (n == 2
&& SSE_CLASS_P (classes[0]) == SSE_CLASS_P (classes[1])))
{
/* The argument is in a single register. */
if (SSE_CLASS_P (classes[0]))
{
avalue[i] = &reg_args->sse[ssecount];
ssecount += n;
}
else
{
avalue[i] = &reg_args->gpr[gprcount];
gprcount += n;
}
}
/* Otherwise, allocate space to make them consecutive. */
else
{
char *a = alloca (16);
int j;
avalue[i] = a;
for (j = 0; j < n; j++, a += 8)
{
if (SSE_CLASS_P (classes[j]))
memcpy (a, &reg_args->sse[ssecount++], 8);
else
memcpy (a, &reg_args->gpr[gprcount++], 8);
}
}
}
/* Invoke the closure. */
closure->fun (cif, rvalue, avalue, closure->user_data);
/* Tell assembly how to perform return type promotions. */
return ret;
}
#endif /* __x86_64__ */

View File

@@ -0,0 +1,81 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for x86 and x86-64.
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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- System specific configurations ----------------------------------- */
#if defined (X86_64) && defined (__i386__)
#undef X86_64
#define X86
#endif
/* ---- Generic type definitions ----------------------------------------- */
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
/* ---- Intel x86 Win32 ---------- */
#ifdef X86_WIN32
FFI_SYSV,
FFI_STDCALL,
/* TODO: Add fastcall support for the sake of completeness */
FFI_DEFAULT_ABI = FFI_SYSV,
#endif
/* ---- Intel x86 and AMD x86-64 - */
#if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__))
FFI_SYSV,
FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
#ifdef __i386__
FFI_DEFAULT_ABI = FFI_SYSV,
#else
FFI_DEFAULT_ABI = FFI_UNIX64,
#endif
#endif
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0
#else
#define FFI_TRAMPOLINE_SIZE 10
#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
#endif
#endif

378
libffi/src/x86/sysv.S Normal file
View File

@@ -0,0 +1,378 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc.
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.
----------------------------------------------------------------------- */
#ifndef __x86_64__
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.text
.globl ffi_prep_args
.align 4
.globl ffi_call_SYSV
.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
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
.LFE1:
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
.align 4
FFI_HIDDEN (ffi_closure_SYSV)
.globl ffi_closure_SYSV
.type ffi_closure_SYSV, @function
ffi_closure_SYSV:
.LFB2:
pushl %ebp
.LCFI2:
movl %esp, %ebp
.LCFI3:
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp) /* resp */
leal 8(%ebp), %edx
movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
leal -12(%ebp), %edx
movl %edx, (%esp) /* &resp */
#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__
call ffi_closure_SYSV_inner
#else
movl %ebx, 8(%esp)
.LCFI7:
call 1f
1: popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
call ffi_closure_SYSV_inner@PLT
movl 8(%esp), %ebx
#endif
movl -12(%ebp), %ecx
cmpl $FFI_TYPE_INT, %eax
je .Lcls_retint
cmpl $FFI_TYPE_FLOAT, %eax
je .Lcls_retfloat
cmpl $FFI_TYPE_DOUBLE, %eax
je .Lcls_retdouble
cmpl $FFI_TYPE_LONGDOUBLE, %eax
je .Lcls_retldouble
cmpl $FFI_TYPE_SINT64, %eax
je .Lcls_retllong
.Lcls_epilogue:
movl %ebp, %esp
popl %ebp
ret
.Lcls_retint:
movl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retfloat:
flds (%ecx)
jmp .Lcls_epilogue
.Lcls_retdouble:
fldl (%ecx)
jmp .Lcls_epilogue
.Lcls_retldouble:
fldt (%ecx)
jmp .Lcls_epilogue
.Lcls_retllong:
movl (%ecx), %eax
movl 4(%ecx), %edx
jmp .Lcls_epilogue
.LFE2:
.size ffi_closure_SYSV, .-ffi_closure_SYSV
#if !FFI_NO_RAW_API
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
#define CIF_FLAGS_OFFSET 20
.align 4
FFI_HIDDEN (ffi_closure_raw_SYSV)
.globl ffi_closure_raw_SYSV
.type ffi_closure_raw_SYSV, @function
ffi_closure_raw_SYSV:
.LFB3:
pushl %ebp
.LCFI4:
movl %esp, %ebp
.LCFI5:
pushl %esi
.LCFI6:
subl $36, %esp
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
movl %edx, 12(%esp) /* user_data */
leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
movl %edx, 8(%esp) /* raw_args */
leal -24(%ebp), %edx
movl %edx, 4(%esp) /* &res */
movl %esi, (%esp) /* cif */
call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
cmpl $FFI_TYPE_INT, %eax
je .Lrcls_retint
cmpl $FFI_TYPE_FLOAT, %eax
je .Lrcls_retfloat
cmpl $FFI_TYPE_DOUBLE, %eax
je .Lrcls_retdouble
cmpl $FFI_TYPE_LONGDOUBLE, %eax
je .Lrcls_retldouble
cmpl $FFI_TYPE_SINT64, %eax
je .Lrcls_retllong
.Lrcls_epilogue:
addl $36, %esp
popl %esi
popl %ebp
ret
.Lrcls_retint:
movl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retfloat:
flds -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retdouble:
fldl -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retldouble:
fldt -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retllong:
movl -24(%ebp), %eax
movl -20(%ebp), %edx
jmp .Lrcls_epilogue
.LFE3:
.size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV
#endif
.section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1:
.long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
.LSCIE1:
.long 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#ifdef __PIC__
.ascii "zR\0" /* CIE Augmentation */
#else
.ascii "\0" /* CIE Augmentation */
#endif
.byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
.byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
.byte 0x8 /* CIE RA Column */
#ifdef __PIC__
.byte 0x1 /* .uleb128 0x1; Augmentation size */
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
#endif
.byte 0xc /* DW_CFA_def_cfa */
.byte 0x4 /* .uleb128 0x4 */
.byte 0x4 /* .uleb128 0x4 */
.byte 0x88 /* DW_CFA_offset, column 0x8 */
.byte 0x1 /* .uleb128 0x1 */
.align 4
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.long .LASFDE1-.Lframe1 /* FDE CIE offset */
#ifdef __PIC__
.long .LFB1-. /* FDE initial location */
#else
.long .LFB1 /* FDE initial location */
#endif
.long .LFE1-.LFB1 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI0-.LFB1
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI1-.LCFI0
.byte 0xd /* DW_CFA_def_cfa_register */
.byte 0x5 /* .uleb128 0x5 */
.align 4
.LEFDE1:
.LSFDE2:
.long .LEFDE2-.LASFDE2 /* FDE Length */
.LASFDE2:
.long .LASFDE2-.Lframe1 /* FDE CIE offset */
#ifdef __PIC__
.long .LFB2-. /* FDE initial location */
#else
.long .LFB2
#endif
.long .LFE2-.LFB2 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI2-.LFB2
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI3-.LCFI2
.byte 0xd /* DW_CFA_def_cfa_register */
.byte 0x5 /* .uleb128 0x5 */
#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI7-.LCFI3
.byte 0x83 /* DW_CFA_offset, column 0x3 */
.byte 0xa /* .uleb128 0xa */
#endif
.align 4
.LEFDE2:
#if !FFI_NO_RAW_API
.LSFDE3:
.long .LEFDE3-.LASFDE3 /* FDE Length */
.LASFDE3:
.long .LASFDE3-.Lframe1 /* FDE CIE offset */
#ifdef __PIC__
.long .LFB3-. /* FDE initial location */
#else
.long .LFB3
#endif
.long .LFE3-.LFB3 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI4-.LFB3
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI5-.LCFI4
.byte 0xd /* DW_CFA_def_cfa_register */
.byte 0x5 /* .uleb128 0x5 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI6-.LCFI5
.byte 0x86 /* DW_CFA_offset, column 0x6 */
.byte 0x3 /* .uleb128 0x3 */
.align 4
.LEFDE3:
#endif
#endif /* ifndef __x86_64__ */

412
libffi/src/x86/unix64.S Normal file
View File

@@ -0,0 +1,412 @@
/* -----------------------------------------------------------------------
unix64.S - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
x86-64 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.
----------------------------------------------------------------------- */
#ifdef __x86_64__
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.text
/* ffi_call_unix64 (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 2
.globl ffi_call_unix64
.type ffi_call_unix64,@function
ffi_call_unix64:
.LUW0:
movq (%rsp), %r10 /* Load return address. */
leaq (%rdi, %rsi), %rax /* Find local stack base. */
movq %rdx, (%rax) /* Save flags. */
movq %rcx, 8(%rax) /* Save raddr. */
movq %rbp, 16(%rax) /* Save old frame pointer. */
movq %r10, 24(%rax) /* Relocate return address. */
movq %rax, %rbp /* Finalize local stack frame. */
.LUW1:
movq %rdi, %r10 /* Save a copy of the register area. */
movq %r8, %r11 /* Save a copy of the target fn. */
movl %r9d, %eax /* Set number of SSE registers. */
/* Load up all argument registers. */
movq (%r10), %rdi
movq 8(%r10), %rsi
movq 16(%r10), %rdx
movq 24(%r10), %rcx
movq 32(%r10), %r8
movq 40(%r10), %r9
testl %eax, %eax
jnz .Lload_sse
.Lret_from_load_sse:
/* Deallocate the reg arg area. */
leaq 176(%r10), %rsp
/* Call the user function. */
call *%r11
/* Deallocate stack arg area; local stack frame in redzone. */
leaq 24(%rbp), %rsp
movq 0(%rbp), %rcx /* Reload flags. */
movq 8(%rbp), %rdi /* Reload raddr. */
movq 16(%rbp), %rbp /* Reload old frame pointer. */
.LUW2:
/* The first byte of the flags contains the FFI_TYPE. */
movzbl %cl, %r10d
leaq .Lstore_table(%rip), %r11
movslq (%r11, %r10, 4), %r10
addq %r11, %r10
jmp *%r10
.section .rodata
.Lstore_table:
.long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */
.long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */
.long .Lst_float-.Lstore_table /* FFI_TYPE_FLOAT */
.long .Lst_double-.Lstore_table /* FFI_TYPE_DOUBLE */
.long .Lst_ldouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
.long .Lst_uint8-.Lstore_table /* FFI_TYPE_UINT8 */
.long .Lst_sint8-.Lstore_table /* FFI_TYPE_SINT8 */
.long .Lst_uint16-.Lstore_table /* FFI_TYPE_UINT16 */
.long .Lst_sint16-.Lstore_table /* FFI_TYPE_SINT16 */
.long .Lst_uint32-.Lstore_table /* FFI_TYPE_UINT32 */
.long .Lst_sint32-.Lstore_table /* FFI_TYPE_SINT32 */
.long .Lst_int64-.Lstore_table /* FFI_TYPE_UINT64 */
.long .Lst_int64-.Lstore_table /* FFI_TYPE_SINT64 */
.long .Lst_struct-.Lstore_table /* FFI_TYPE_STRUCT */
.long .Lst_int64-.Lstore_table /* FFI_TYPE_POINTER */
.text
.align 2
.Lst_void:
ret
.align 2
.Lst_uint8:
movzbq %al, %rax
movq %rax, (%rdi)
ret
.align 2
.Lst_sint8:
movsbq %al, %rax
movq %rax, (%rdi)
ret
.align 2
.Lst_uint16:
movzwq %ax, %rax
movq %rax, (%rdi)
.align 2
.Lst_sint16:
movswq %ax, %rax
movq %rax, (%rdi)
ret
.align 2
.Lst_uint32:
movl %eax, %eax
movq %rax, (%rdi)
.align 2
.Lst_sint32:
cltq
movq %rax, (%rdi)
ret
.align 2
.Lst_int64:
movq %rax, (%rdi)
ret
.align 2
.Lst_float:
movss %xmm0, (%rdi)
ret
.align 2
.Lst_double:
movsd %xmm0, (%rdi)
ret
.Lst_ldouble:
fstpt (%rdi)
ret
.align 2
.Lst_struct:
leaq -20(%rsp), %rsi /* Scratch area in redzone. */
/* We have to locate the values now, and since we don't want to
write too much data into the user's return value, we spill the
value to a 16 byte scratch area first. Bits 8, 9, and 10
control where the values are located. Only one of the three
bits will be set; see ffi_prep_cif_machdep for the pattern. */
movd %xmm0, %r10
movd %xmm1, %r11
testl $0x100, %ecx
cmovnz %rax, %rdx
cmovnz %r10, %rax
testl $0x200, %ecx
cmovnz %r10, %rdx
testl $0x400, %ecx
cmovnz %r10, %rax
cmovnz %r11, %rdx
movq %rax, (%rsi)
movq %rdx, 8(%rsi)
/* Bits 12-31 contain the true size of the structure. Copy from
the scratch area to the true destination. */
shrl $12, %ecx
rep movsb
ret
/* Many times we can avoid loading any SSE registers at all.
It's not worth an indirect jump to load the exact set of
SSE registers needed; zero or all is a good compromise. */
.align 2
.LUW3:
.Lload_sse:
movdqa 48(%r10), %xmm0
movdqa 64(%r10), %xmm1
movdqa 80(%r10), %xmm2
movdqa 96(%r10), %xmm3
movdqa 112(%r10), %xmm4
movdqa 128(%r10), %xmm5
movdqa 144(%r10), %xmm6
movdqa 160(%r10), %xmm7
jmp .Lret_from_load_sse
.LUW4:
.size ffi_call_unix64,.-ffi_call_unix64
.align 2
.globl ffi_closure_unix64
.type ffi_closure_unix64,@function
ffi_closure_unix64:
.LUW5:
/* The carry flag is set by the trampoline iff SSE registers
are used. Don't clobber it before the branch instruction. */
leaq -200(%rsp), %rsp
.LUW6:
movq %rdi, (%rsp)
movq %rsi, 8(%rsp)
movq %rdx, 16(%rsp)
movq %rcx, 24(%rsp)
movq %r8, 32(%rsp)
movq %r9, 40(%rsp)
jc .Lsave_sse
.Lret_from_save_sse:
movq %r10, %rdi
leaq 176(%rsp), %rsi
movq %rsp, %rdx
leaq 208(%rsp), %rcx
call ffi_closure_unix64_inner@PLT
/* Deallocate stack frame early; return value is now in redzone. */
addq $200, %rsp
.LUW7:
/* The first byte of the return value contains the FFI_TYPE. */
movzbl %al, %r10d
leaq .Lload_table(%rip), %r11
movslq (%r11, %r10, 4), %r10
addq %r11, %r10
jmp *%r10
.section .rodata
.Lload_table:
.long .Lld_void-.Lload_table /* FFI_TYPE_VOID */
.long .Lld_int32-.Lload_table /* FFI_TYPE_INT */
.long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */
.long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */
.long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */
.long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */
.long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */
.long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */
.long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */
.long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */
.long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */
.long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */
.long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */
.long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */
.long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */
.text
.align 2
.Lld_void:
ret
.align 2
.Lld_int8:
movzbl -24(%rsp), %eax
ret
.align 2
.Lld_int16:
movzwl -24(%rsp), %eax
ret
.align 2
.Lld_int32:
movl -24(%rsp), %eax
ret
.align 2
.Lld_int64:
movq -24(%rsp), %rax
ret
.align 2
.Lld_float:
movss -24(%rsp), %xmm0
ret
.align 2
.Lld_double:
movsd -24(%rsp), %xmm0
ret
.align 2
.Lld_ldouble:
fldt -24(%rsp)
ret
.align 2
.Lld_struct:
/* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
%rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading
both rdx and xmm1 with the second word. For the remaining,
bit 8 set means xmm0 gets the second word, and bit 9 means
that rax gets the second word. */
movq -24(%rsp), %rcx
movq -16(%rsp), %rdx
movq -16(%rsp), %xmm1
testl $0x100, %eax
cmovnz %rdx, %rcx
movd %rcx, %xmm0
testl $0x200, %eax
movq -24(%rsp), %rax
cmovnz %rdx, %rax
ret
/* See the comment above .Lload_sse; the same logic applies here. */
.align 2
.LUW8:
.Lsave_sse:
movdqa %xmm0, 48(%rsp)
movdqa %xmm1, 64(%rsp)
movdqa %xmm2, 80(%rsp)
movdqa %xmm3, 96(%rsp)
movdqa %xmm4, 112(%rsp)
movdqa %xmm5, 128(%rsp)
movdqa %xmm6, 144(%rsp)
movdqa %xmm7, 160(%rsp)
jmp .Lret_from_save_sse
.LUW9:
.size ffi_closure_unix64,.-ffi_closure_unix64
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1 /* CIE Length */
.LSCIE1:
.long 0 /* CIE Identifier Tag */
.byte 1 /* CIE Version */
.ascii "zR\0" /* CIE Augmentation */
.uleb128 1 /* CIE Code Alignment Factor */
.sleb128 -8 /* CIE Data Alignment Factor */
.byte 0x10 /* CIE RA Column */
.uleb128 1 /* Augmentation size */
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
.uleb128 7
.uleb128 8
.byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */
.uleb128 1
.align 8
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.long .LASFDE1-.Lframe1 /* FDE CIE offset */
.long .LUW0-. /* FDE initial location */
.long .LUW4-.LUW0 /* FDE address range */
.uleb128 0x0 /* Augmentation size */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LUW1-.LUW0
/* New stack frame based off rbp. This is a itty bit of unwind
trickery in that the CFA *has* changed. There is no easy way
to describe it correctly on entry to the function. Fortunately,
it doesn't matter too much since at all points we can correctly
unwind back to ffi_call. Note that the location to which we
moved the return address is (the new) CFA-8, so from the
perspective of the unwind info, it hasn't moved. */
.byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */
.uleb128 6
.uleb128 32
.byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */
.uleb128 2
.byte 0xa /* DW_CFA_remember_state */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LUW2-.LUW1
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
.uleb128 7
.uleb128 8
.byte 0xc0+6 /* DW_CFA_restore, %rbp */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LUW3-.LUW2
.byte 0xb /* DW_CFA_restore_state */
.align 8
.LEFDE1:
.LSFDE3:
.long .LEFDE3-.LASFDE3 /* FDE Length */
.LASFDE3:
.long .LASFDE3-.Lframe1 /* FDE CIE offset */
.long .LUW5-. /* FDE initial location */
.long .LUW9-.LUW5 /* FDE address range */
.uleb128 0x0 /* Augmentation size */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LUW6-.LUW5
.byte 0xe /* DW_CFA_def_cfa_offset */
.uleb128 208
.byte 0xa /* DW_CFA_remember_state */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LUW7-.LUW6
.byte 0xe /* DW_CFA_def_cfa_offset */
.uleb128 8
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LUW8-.LUW7
.byte 0xb /* DW_CFA_restore_state */
.align 8
.LEFDE3:
#endif /* __x86_64__ */

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

@@ -0,0 +1,373 @@
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
Copyright (c) 2001 John Beniton
Copyright (c) 2002 Ranjit Mathew
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 <fficonfig.h>
#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
# FIXME: Align the stack to a 128-bit boundary to avoid
# potential performance hits.
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 retstruct1b
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
retstruct1b:
cmpl $FFI_TYPE_SINT8,%ecx
jne retstruct2b
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movb %al,0(%ecx)
jmp epilogue
retstruct2b:
cmpl $FFI_TYPE_SINT16,%ecx
jne retstruct
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movw %ax,0(%ecx)
jmp epilogue
retstruct:
# Nothing to do!
noretval:
epilogue:
movl %ebp,%esp
popl %ebp
ret
.ffi_call_SYSV_end:
# This assumes we are using gas.
.balign 16
.globl _ffi_call_STDCALL
_ffi_call_STDCALL:
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
# FIXME: Align the stack to a 128-bit boundary to avoid
# potential performance hits.
call *28(%ebp)
# stdcall functions pop arguments off the stack themselves
# 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 sc_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 sc_noretval
fstp %st(0)
jmp sc_epilogue
sc_retint:
cmpl $FFI_TYPE_INT,%ecx
jne sc_retfloat
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
jmp sc_epilogue
sc_retfloat:
cmpl $FFI_TYPE_FLOAT,%ecx
jne sc_retdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstps (%ecx)
jmp sc_epilogue
sc_retdouble:
cmpl $FFI_TYPE_DOUBLE,%ecx
jne sc_retlongdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpl (%ecx)
jmp sc_epilogue
sc_retlongdouble:
cmpl $FFI_TYPE_LONGDOUBLE,%ecx
jne sc_retint64
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpt (%ecx)
jmp sc_epilogue
sc_retint64:
cmpl $FFI_TYPE_SINT64,%ecx
jne sc_retstruct1b
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
sc_retstruct1b:
cmpl $FFI_TYPE_SINT8,%ecx
jne sc_retstruct2b
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movb %al,0(%ecx)
jmp sc_epilogue
sc_retstruct2b:
cmpl $FFI_TYPE_SINT16,%ecx
jne sc_retstruct
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movw %ax,0(%ecx)
jmp sc_epilogue
sc_retstruct:
# Nothing to do!
sc_noretval:
sc_epilogue:
movl %ebp,%esp
popl %ebp
ret
.ffi_call_STDCALL_end:
.globl _ffi_closure_SYSV
_ffi_closure_SYSV:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp) /* resp */
leal 8(%ebp), %edx
movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
leal -12(%ebp), %edx
movl %edx, (%esp) /* &resp */
call _ffi_closure_SYSV_inner
movl -12(%ebp), %ecx
cmpl $FFI_TYPE_INT, %eax
je .Lcls_retint
cmpl $FFI_TYPE_FLOAT, %eax
je .Lcls_retfloat
cmpl $FFI_TYPE_DOUBLE, %eax
je .Lcls_retdouble
cmpl $FFI_TYPE_LONGDOUBLE, %eax
je .Lcls_retldouble
cmpl $FFI_TYPE_SINT64, %eax
je .Lcls_retllong
cmpl $FFI_TYPE_SINT8, %eax /* 1-byte struct */
je .Lcls_retstruct1
cmpl $FFI_TYPE_SINT16, %eax /* 2-bytes struct */
je .Lcls_retstruct2
.Lcls_epilogue:
movl %ebp, %esp
popl %ebp
ret
.Lcls_retint:
movl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retfloat:
flds (%ecx)
jmp .Lcls_epilogue
.Lcls_retdouble:
fldl (%ecx)
jmp .Lcls_epilogue
.Lcls_retldouble:
fldt (%ecx)
jmp .Lcls_epilogue
.Lcls_retllong:
movl (%ecx), %eax
movl 4(%ecx), %edx
jmp .Lcls_epilogue
.Lcls_retstruct1:
movsbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct2:
movswl (%ecx), %eax
jmp .Lcls_epilogue
.ffi_closure_SYSV_end:
#if !FFI_NO_RAW_API
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
#define CIF_FLAGS_OFFSET 20
.balign 16
.globl _ffi_closure_raw_SYSV
_ffi_closure_raw_SYSV:
pushl %ebp
movl %esp, %ebp
pushl %esi
subl $36, %esp
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
movl %edx, 12(%esp) /* user_data */
leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
movl %edx, 8(%esp) /* raw_args */
leal -24(%ebp), %edx
movl %edx, 4(%esp) /* &res */
movl %esi, (%esp) /* cif */
call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
cmpl $FFI_TYPE_INT, %eax
je .Lrcls_retint
cmpl $FFI_TYPE_FLOAT, %eax
je .Lrcls_retfloat
cmpl $FFI_TYPE_DOUBLE, %eax
je .Lrcls_retdouble
cmpl $FFI_TYPE_LONGDOUBLE, %eax
je .Lrcls_retldouble
cmpl $FFI_TYPE_SINT64, %eax
je .Lrcls_retllong
.Lrcls_epilogue:
addl $36, %esp
popl %esi
popl %ebp
ret
.Lrcls_retint:
movl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retfloat:
flds -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retdouble:
fldl -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retldouble:
fldt -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retllong:
movl -24(%ebp), %eax
movl -20(%ebp), %edx
jmp .Lrcls_epilogue
.ffi_closure_raw_SYSV_end:
#endif