Import of v1 code.
This commit is contained in:
128
libffi/src/powerpc/asm.h
Normal file
128
libffi/src/powerpc/asm.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
asm.h - Copyright (c) 1998 Geoffrey Keating
|
||||
|
||||
PowerPC Assembly glue.
|
||||
|
||||
$Id: asm.h,v 1.1 1998/11/29 16:48:16 green Exp $
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
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
|
||||
|
||||
423
libffi/src/powerpc/ffi.c
Normal file
423
libffi/src/powerpc/ffi.c
Normal file
@@ -0,0 +1,423 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 1998 Geoffrey Keating
|
||||
|
||||
PowerPC Foreign Function Interface
|
||||
|
||||
$Id: ffi.c,v 1.1 1998/11/29 16:48:16 green Exp $
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
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>
|
||||
|
||||
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_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 SYSV ABI. */
|
||||
enum {
|
||||
NUM_GPR_ARG_REGISTERS = 8,
|
||||
NUM_FPR_ARG_REGISTERS = 8
|
||||
};
|
||||
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_SYSV 4bytes | higher addresses
|
||||
|--------------------------------------------|
|
||||
| Previous backchain pointer 4 | stack pointer here
|
||||
|--------------------------------------------|<+ <<< on entry to
|
||||
| Saved r28-r31 4*4 | | ffi_call_SYSV
|
||||
|--------------------------------------------| |
|
||||
| GPR registers r3-r10 8*4 | | ffi_call_SYSV
|
||||
|--------------------------------------------| |
|
||||
| FPR registers f1-f8 (optional) 8*8 | |
|
||||
|--------------------------------------------| | stack |
|
||||
| Space for copied structures | | grows |
|
||||
|--------------------------------------------| | down V
|
||||
| Parameters that didn't fit in registers | |
|
||||
|--------------------------------------------| | lower addresses
|
||||
| Space for callee's LR 4 | |
|
||||
|--------------------------------------------| | stack pointer here
|
||||
| Current backchain pointer 4 |-/ during
|
||||
|--------------------------------------------| <<< ffi_call_SYSV
|
||||
|
||||
*/
|
||||
|
||||
/*@-exportheader@*/
|
||||
void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
|
||||
/*@=exportheader@*/
|
||||
{
|
||||
const unsigned bytes = ecif->cif->bytes;
|
||||
const unsigned flags = ecif->cif->flags;
|
||||
|
||||
/* 'stacktop' points at the previous backchain pointer. */
|
||||
unsigned *const stacktop = stack + (ecif->cif->bytes / sizeof(unsigned));
|
||||
|
||||
/* 'gpr_base' points at the space for gpr3, and grows upwards as
|
||||
we use GPR registers. */
|
||||
unsigned *gpr_base = stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
|
||||
int intarg_count = 0;
|
||||
|
||||
/* 'fpr_base' points at the space for fpr1, and grows upwards as
|
||||
we use FPR registers. */
|
||||
double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS;
|
||||
int fparg_count = 0;
|
||||
|
||||
/* 'copy_space' grows down as we put structures in it. It should
|
||||
stay 16-byte aligned. */
|
||||
char *copy_space = ((flags & FLAG_FP_ARGUMENTS)
|
||||
? (char *)fpr_base
|
||||
: (char *)gpr_base);
|
||||
|
||||
/* 'next_arg' grows up as we put parameters in it. */
|
||||
unsigned *next_arg = stack + 2;
|
||||
|
||||
int i;
|
||||
ffi_type **ptr;
|
||||
double double_tmp;
|
||||
void **p_argv;
|
||||
size_t struct_copy_size;
|
||||
unsigned gprvalue;
|
||||
|
||||
/* Check that everything starts aligned properly. */
|
||||
FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
|
||||
FFI_ASSERT(((unsigned)(char *)copy_space & 0xF) == 0);
|
||||
FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
|
||||
FFI_ASSERT((bytes & 0xF) == 0);
|
||||
FFI_ASSERT(copy_space >= (char *)next_arg);
|
||||
|
||||
/* Deal with return values that are actually pass-by-reference. */
|
||||
if (flags & FLAG_RETVAL_REFERENCE)
|
||||
{
|
||||
*gpr_base++ = (unsigned)(char *)ecif->rvalue;
|
||||
intarg_count++;
|
||||
}
|
||||
|
||||
/* Now for the arguments. */
|
||||
p_argv = ecif->avalue;
|
||||
for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
|
||||
i > 0;
|
||||
i--, ptr++, p_argv++)
|
||||
{
|
||||
switch ((*ptr)->type)
|
||||
{
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
if ((*ptr)->type == FFI_TYPE_FLOAT)
|
||||
double_tmp = *(float *)*p_argv;
|
||||
else
|
||||
double_tmp = *(double *)*p_argv;
|
||||
|
||||
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
|
||||
{
|
||||
if (intarg_count%2 != 0)
|
||||
{
|
||||
intarg_count++;
|
||||
next_arg++;
|
||||
}
|
||||
*(double *)next_arg = double_tmp;
|
||||
next_arg += 2;
|
||||
}
|
||||
else
|
||||
*fpr_base++ = double_tmp;
|
||||
fparg_count++;
|
||||
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
|
||||
intarg_count++;
|
||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
|
||||
{
|
||||
if (intarg_count%2 != 0)
|
||||
{
|
||||
intarg_count++;
|
||||
next_arg++;
|
||||
}
|
||||
*(long long *)next_arg = *(long long *)*p_argv;
|
||||
next_arg += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(long long *)gpr_base = *(long long *)*p_argv;
|
||||
gpr_base += 2;
|
||||
}
|
||||
intarg_count += 2;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
#endif
|
||||
struct_copy_size = ((*ptr)->size + 15) & ~0xF;
|
||||
copy_space -= struct_copy_size;
|
||||
memcpy(copy_space, (char *)*p_argv, (*ptr)->size);
|
||||
|
||||
gprvalue = (unsigned)copy_space;
|
||||
|
||||
FFI_ASSERT(copy_space > (char *)next_arg);
|
||||
FFI_ASSERT(flags & FLAG_ARG_NEEDS_COPY);
|
||||
goto putgpr;
|
||||
|
||||
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_INT:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_POINTER:
|
||||
gprvalue = *(unsigned *)*p_argv;
|
||||
putgpr:
|
||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
|
||||
*next_arg++ = gprvalue;
|
||||
else
|
||||
*gpr_base++ = gprvalue;
|
||||
intarg_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that we didn't overrun the stack... */
|
||||
FFI_ASSERT(copy_space >= (char *)next_arg);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
/* All this is for the SYSV ABI. */
|
||||
int i;
|
||||
ffi_type **ptr;
|
||||
unsigned bytes;
|
||||
int fparg_count = 0, intarg_count = 0;
|
||||
unsigned flags = 0;
|
||||
unsigned struct_copy_size = 0;
|
||||
|
||||
/* All the machine-independent calculation of cif->bytes will be wrong.
|
||||
Redo the calculation for SYSV. */
|
||||
|
||||
/* Space for the frame pointer, callee's LR, and the asm's temp regs. */
|
||||
bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof(int);
|
||||
|
||||
/* Space for the GPR registers. */
|
||||
bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
|
||||
|
||||
/* 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;
|
||||
- Larger structures and long double (if not equivalent to double) values
|
||||
are allocated space and a pointer is passed as the first argument. */
|
||||
switch (cif->rtype->type)
|
||||
{
|
||||
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:
|
||||
if (cif->abi != FFI_GCC_SYSV)
|
||||
if (cif->rtype->size <= 4)
|
||||
break;
|
||||
else if (cif->rtype->size <= 8)
|
||||
{
|
||||
flags |= FLAG_RETURNS_64BITS;
|
||||
break;
|
||||
}
|
||||
/* else fall through. */
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
#endif
|
||||
intarg_count++;
|
||||
flags |= FLAG_RETVAL_REFERENCE;
|
||||
/* Fall through. */
|
||||
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 and long doubles (if not equivalent
|
||||
to double) are passed as a pointer to a copy of the structure.
|
||||
Stuff on the stack needs to keep proper alignment. */
|
||||
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
|
||||
{
|
||||
switch ((*ptr)->type)
|
||||
{
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
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;
|
||||
|
||||
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:
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
#endif
|
||||
/* We must allocate space for a copy of these to enforce
|
||||
pass-by-value. Pad the space up to a multiple of 16
|
||||
bytes (the maximum alignment required for anything under
|
||||
the SYSV ABI). */
|
||||
struct_copy_size += ((*ptr)->size + 15) & ~0xF;
|
||||
/* Fall through (allocate space for the pointer). */
|
||||
|
||||
default:
|
||||
/* Everything else is passed as a 4-byte word in a GPR, either
|
||||
the object itself or a pointer to it. */
|
||||
intarg_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fparg_count != 0)
|
||||
flags |= FLAG_FP_ARGUMENTS;
|
||||
if (intarg_count > 4)
|
||||
flags |= FLAG_4_GPR_ARGUMENTS;
|
||||
if (struct_copy_size != 0)
|
||||
flags |= FLAG_ARG_NEEDS_COPY;
|
||||
|
||||
/* Space for the FPR registers, if needed. */
|
||||
if (fparg_count != 0)
|
||||
bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
|
||||
|
||||
/* Stack space. */
|
||||
if (intarg_count > NUM_GPR_ARG_REGISTERS)
|
||||
bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof(int);
|
||||
if (fparg_count > NUM_FPR_ARG_REGISTERS)
|
||||
bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof(double);
|
||||
|
||||
/* The stack space allocated needs to be a multiple of 16 bytes. */
|
||||
bytes = (bytes + 15) & ~0xF;
|
||||
|
||||
/* Add in the space for the copied structures. */
|
||||
bytes += struct_copy_size;
|
||||
|
||||
cif->flags = flags;
|
||||
cif->bytes = bytes;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
/*@-declundef@*/
|
||||
/*@-exportheader@*/
|
||||
extern void ffi_call_SYSV(/*@out@*/ extended_cif *,
|
||||
unsigned, unsigned,
|
||||
/*@out@*/ unsigned *,
|
||||
void (*fn)());
|
||||
/*@=declundef@*/
|
||||
/*@=exportheader@*/
|
||||
|
||||
void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
||||
void (*fn)(),
|
||||
/*@out@*/ void *rvalue,
|
||||
/*@dependent@*/ 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))
|
||||
{
|
||||
/*@-sysunrecog@*/
|
||||
ecif.rvalue = alloca(cif->rtype->size);
|
||||
/*@=sysunrecog@*/
|
||||
}
|
||||
else
|
||||
ecif.rvalue = rvalue;
|
||||
|
||||
|
||||
switch (cif->abi)
|
||||
{
|
||||
case FFI_SYSV:
|
||||
case FFI_GCC_SYSV:
|
||||
/*@-usedef@*/
|
||||
ffi_call_SYSV(&ecif, -cif->bytes,
|
||||
cif->flags, ecif.rvalue, fn);
|
||||
/*@=usedef@*/
|
||||
break;
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
119
libffi/src/powerpc/sysv.S
Normal file
119
libffi/src/powerpc/sysv.S
Normal file
@@ -0,0 +1,119 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
sysv.h - Copyright (c) 1998 Geoffrey Keating
|
||||
|
||||
PowerPC Assembly glue.
|
||||
|
||||
$Id: sysv.S,v 1.1 1998/11/29 16:48:16 green Exp $
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
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 <ffi.h>
|
||||
#include <powerpc/asm.h>
|
||||
|
||||
.globl ffi_prep_args
|
||||
ENTRY(ffi_call_SYSV)
|
||||
/* 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, 4(%r8)
|
||||
|
||||
/* 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
|
||||
bl JUMPTARGET(ffi_prep_args)
|
||||
|
||||
/* 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- 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)
|
||||
b L(done_return_value)
|
||||
L(float_return_value):
|
||||
stfs %f1,0(%r30)
|
||||
b L(done_return_value)
|
||||
END(ffi_call_SYSV)
|
||||
Reference in New Issue
Block a user