Pulled in libffi from gcc trunk.
Fixed build and install for standalone use.
This commit is contained in:
252
libffi/src/alpha/ffi.c
Normal file
252
libffi/src/alpha/ffi.c
Normal 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;
|
||||
}
|
||||
48
libffi/src/alpha/ffitarget.h
Normal file
48
libffi/src/alpha/ffitarget.h
Normal 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
359
libffi/src/alpha/osf.S
Normal 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
170
libffi/src/arm/ffi.c
Normal 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;
|
||||
}
|
||||
}
|
||||
47
libffi/src/arm/ffitarget.h
Normal file
47
libffi/src/arm/ffitarget.h
Normal 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
209
libffi/src/arm/sysv.S
Normal 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
381
libffi/src/cris/ffi.c
Normal 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;
|
||||
}
|
||||
50
libffi/src/cris/ffitarget.h
Normal file
50
libffi/src/cris/ffitarget.h
Normal 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
215
libffi/src/cris/sysv.S
Normal 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
58
libffi/src/debug.c
Normal 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
130
libffi/src/frv/eabi.S
Normal 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
287
libffi/src/frv/ffi.c
Normal 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;
|
||||
}
|
||||
60
libffi/src/frv/ffitarget.h
Normal file
60
libffi/src/frv/ffitarget.h
Normal 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
578
libffi/src/ia64/ffi.c
Normal 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;
|
||||
}
|
||||
49
libffi/src/ia64/ffitarget.h
Normal file
49
libffi/src/ia64/ffitarget.h
Normal 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
|
||||
|
||||
39
libffi/src/ia64/ia64_flags.h
Normal file
39
libffi/src/ia64/ia64_flags.h
Normal 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
555
libffi/src/ia64/unix.S
Normal 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
337
libffi/src/java_raw_api.c
Normal 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
231
libffi/src/m32r/ffi.c
Normal 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;
|
||||
}
|
||||
}
|
||||
48
libffi/src/m32r/ffitarget.h
Normal file
48
libffi/src/m32r/ffitarget.h
Normal 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
121
libffi/src/m32r/sysv.S
Normal 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
176
libffi/src/m68k/ffi.c
Normal 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;
|
||||
}
|
||||
}
|
||||
47
libffi/src/m68k/ffitarget.h
Normal file
47
libffi/src/m68k/ffitarget.h
Normal 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
97
libffi/src/m68k/sysv.S
Normal 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
648
libffi/src/mips/ffi.c
Normal 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
167
libffi/src/mips/ffitarget.h
Normal 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
320
libffi/src/mips/n32.S
Normal 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
377
libffi/src/mips/o32.S
Normal 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
706
libffi/src/pa/ffi.c
Normal 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
76
libffi/src/pa/ffitarget.h
Normal 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
367
libffi/src/pa/hpux32.S
Normal 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
356
libffi/src/pa/linux.S
Normal 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
225
libffi/src/powerpc/aix.S
Normal 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)
|
||||
247
libffi/src/powerpc/aix_closure.S
Normal file
247
libffi/src/powerpc/aix_closure.S
Normal 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
125
libffi/src/powerpc/asm.h
Normal 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
245
libffi/src/powerpc/darwin.S
Normal 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
|
||||
317
libffi/src/powerpc/darwin_closure.S
Normal file
317
libffi/src/powerpc/darwin_closure.S
Normal 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
1298
libffi/src/powerpc/ffi.c
Normal file
File diff suppressed because it is too large
Load Diff
799
libffi/src/powerpc/ffi_darwin.c
Normal file
799
libffi/src/powerpc/ffi_darwin.c
Normal 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;
|
||||
}
|
||||
105
libffi/src/powerpc/ffitarget.h
Normal file
105
libffi/src/powerpc/ffitarget.h
Normal 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
|
||||
177
libffi/src/powerpc/linux64.S
Normal file
177
libffi/src/powerpc/linux64.S
Normal 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
|
||||
206
libffi/src/powerpc/linux64_closure.S
Normal file
206
libffi/src/powerpc/linux64_closure.S
Normal 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
|
||||
283
libffi/src/powerpc/ppc_closure.S
Normal file
283
libffi/src/powerpc/ppc_closure.S
Normal 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
219
libffi/src/powerpc/sysv.S
Normal 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
160
libffi/src/prep_cif.c
Normal 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
239
libffi/src/raw_api.c
Normal 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
751
libffi/src/s390/ffi.c
Normal 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 ============================*/
|
||||
|
||||
59
libffi/src/s390/ffitarget.h
Normal file
59
libffi/src/s390/ffitarget.h
Normal 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
429
libffi/src/s390/sysv.S
Normal 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
713
libffi/src/sh/ffi.c
Normal 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
48
libffi/src/sh/ffitarget.h
Normal 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
845
libffi/src/sh/sysv.S
Normal 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
455
libffi/src/sh64/ffi.c
Normal 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);
|
||||
}
|
||||
|
||||
52
libffi/src/sh64/ffitarget.h
Normal file
52
libffi/src/sh64/ffitarget.h
Normal 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
533
libffi/src/sh64/sysv.S
Normal 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
608
libffi/src/sparc/ffi.c
Normal 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;
|
||||
}
|
||||
65
libffi/src/sparc/ffitarget.h
Normal file
65
libffi/src/sparc/ffitarget.h
Normal 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
267
libffi/src/sparc/v8.S
Normal 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
302
libffi/src/sparc/v9.S
Normal 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
60
libffi/src/types.c
Normal 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
403
libffi/src/x86/darwin.S
Normal 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
415
libffi/src/x86/darwin64.S
Normal 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
432
libffi/src/x86/ffi.c
Normal 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
569
libffi/src/x86/ffi64.c
Normal 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 (®_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] = ®_args->sse[ssecount];
|
||||
ssecount += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
avalue[i] = ®_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, ®_args->sse[ssecount++], 8);
|
||||
else
|
||||
memcpy (a, ®_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__ */
|
||||
81
libffi/src/x86/ffitarget.h
Normal file
81
libffi/src/x86/ffitarget.h
Normal 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
378
libffi/src/x86/sysv.S
Normal 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
412
libffi/src/x86/unix64.S
Normal 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
373
libffi/src/x86/win32.S
Normal 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
|
||||
Reference in New Issue
Block a user