diff options
author | Matthias Benkard <code@mail.matthias.benkard.de> | 2008-01-26 12:06:34 +0100 |
---|---|---|
committer | Matthias Benkard <code@mail.matthias.benkard.de> | 2008-01-26 12:06:34 +0100 |
commit | 181d8ded82d49d0133d9d6fd1631d9816c970bfa (patch) | |
tree | c2791efcee34197c93ed964873c1ff30bf398330 /libffi/src/pa | |
parent | 28a686ef16077f75afbfa3d315cd268680e11b75 (diff) |
Import libffi from PyObjC 1.3.7.
darcs-hash:129bccb59266f997deac9b0353aea2d2d4049f92
Diffstat (limited to 'libffi/src/pa')
-rw-r--r-- | libffi/src/pa/ffi.c | 603 | ||||
-rw-r--r-- | libffi/src/pa/ffitarget.h | 57 | ||||
-rw-r--r-- | libffi/src/pa/linux.S | 281 |
3 files changed, 941 insertions, 0 deletions
diff --git a/libffi/src/pa/ffi.c b/libffi/src/pa/ffi.c new file mode 100644 index 0000000..57331fe --- /dev/null +++ b/libffi/src/pa/ffi.c @@ -0,0 +1,603 @@ +/* ----------------------------------------------------------------------- + ffi.c - (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. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +#define ROUND_UP(v, a) (((size_t)(v) + (a) - 1) & ~((a) - 1)) +#define ROUND_DOWN(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. */ + + if (sz <= 1) + return FFI_TYPE_UINT8; + else if (sz == 2) + return FFI_TYPE_UINT16; + else if (sz == 3) + return FFI_TYPE_SMALL_STRUCT1; + else if (sz == 4) + return FFI_TYPE_UINT32; + else if (sz <= 6) + return FFI_TYPE_SMALL_STRUCT2; + else if (sz <= 8) + return FFI_TYPE_UINT64; + 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 + + First 4 non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23 + First 2 non-FP 64-bit args are passed in register pairs, starting + on an even numbered register (i.e. r26/r25 and r24+r23) + First 4 FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L + First 2 FP 64-bit arguments are passed in fr5 and fr7 + The rest 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. */ + +/*@-exportheader@*/ +void ffi_prep_args_LINUX(UINT32 *stack, extended_cif *ecif, unsigned bytes) +/*@=exportheader@*/ +{ + register unsigned int i; + register ffi_type **p_arg; + register void **p_argv; + unsigned int slot = FIRST_ARG_SLOT - 1; + char *dest_cpy; + + 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: + slot++; + *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv); + break; + + case FFI_TYPE_UINT8: + slot++; + *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv); + break; + + case FFI_TYPE_SINT16: + slot++; + *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT16: + slot++; + *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + slot++; + 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: + slot += 2; + if (slot & 1) + slot++; + + *(UINT32 *)(stack - slot) = (*(UINT64 *)(*p_argv)) >> 32; + *(UINT32 *)(stack - slot + 1) = (*(UINT64 *)(*p_argv)) & 0xffffffffUL; + break; + + case FFI_TYPE_FLOAT: + /* First 4 args go in fr4L - fr7L */ + slot++; + switch (slot - FIRST_ARG_SLOT) + { + case 0: fldw(*p_argv, fr4); break; + case 1: fldw(*p_argv, fr5); break; + case 2: fldw(*p_argv, fr6); break; + case 3: fldw(*p_argv, fr7); break; + default: + /* Other ones are just passed on the stack. */ + debug(3, "Storing UINT32(float) in slot %u\n", slot); + *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv); + break; + } + break; + + case FFI_TYPE_DOUBLE: + slot += 2; + if (slot & 1) + slot++; + switch (slot - FIRST_ARG_SLOT + 1) + { + /* First 2 args go in fr5, fr7 */ + case 2: fldd(*p_argv, fr5); break; + case 4: fldd(*p_argv, fr7); break; + default: + debug(3, "Storing UINT64(double) at slot %u\n", slot); + *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv); + break; + } + 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) + { + slot++; + dest_cpy = (char *)(stack - slot); + dest_cpy += 4 - (*p_arg)->size; + memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size); + } + else if ((*p_arg)->size <= 8) + { + slot += 2; + if (slot & 1) + slot++; + dest_cpy = (char *)(stack - slot); + dest_cpy += 8 - (*p_arg)->size; + memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size); + } + else + { + slot++; + *(UINT32 *)(stack - slot) = (UINT32)(*p_argv); + } + break; + + default: + FFI_ASSERT(0); + } + + p_arg++; + p_argv++; + } + + /* Make sure we didn't mess up and scribble on the stack. */ + { + 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_LINUX(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; + + 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; + + 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_LINUX: + ffi_size_stack_LINUX(cif); + break; + + default: + FFI_ASSERT(0); + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_LINUX(void (*)(UINT32 *, extended_cif *, unsigned), + /*@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_LINUX: + /*@-usedef@*/ + debug(2, "Calling ffi_call_LINUX: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn); + ffi_call_LINUX(ffi_prep_args_LINUX, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + 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. */ +UINT32 ffi_closure_inner_LINUX(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, slot = FIRST_ARG_SLOT - 1; + 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: + slot++; + avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + slot += 2; + if (slot & 1) + slot++; + avalue[i] = (void *)(stack - slot); + break; + + case FFI_TYPE_FLOAT: + slot++; + 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; + } + avalue[i] = (void *)(stack - slot); + break; + + case FFI_TYPE_DOUBLE: + slot += 2; + if (slot & 1) + slot++; + switch (slot - FIRST_ARG_SLOT + 1) + { + case 2: fstd(fr5, (void *)(stack - slot)); break; + case 4: fstd(fr7, (void *)(stack - slot)); break; + } + 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) { + slot++; + avalue[i] = (void *)(stack - slot) + sizeof(UINT32) - + (*p_arg)->size; + } else if ((*p_arg)->size <= 8) { + slot += 2; + if (slot & 1) + slot++; + avalue[i] = (void *)(stack - slot) + sizeof(UINT64) - + (*p_arg)->size; + } else { + slot++; + avalue[i] = (void *) *(stack - slot); + } + break; + + default: + FFI_ASSERT(0); + } + + p_arg++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + debug(3, "after calling function, ret[0] = %d, ret[1] = %d\n", ret[0], ret[1]); + + /* Store the result */ + switch (cif->flags) + { + case FFI_TYPE_UINT8: + *(stack - FIRST_ARG_SLOT) = *(UINT8 *)&ret[0]; + break; + case FFI_TYPE_SINT8: + *(stack - FIRST_ARG_SLOT) = *(SINT8 *)&ret[0]; + break; + case FFI_TYPE_UINT16: + *(stack - FIRST_ARG_SLOT) = *(UINT16 *)&ret[0]; + break; + case FFI_TYPE_SINT16: + *(stack - FIRST_ARG_SLOT) = *(SINT16 *)&ret[0]; + break; + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + *(stack - FIRST_ARG_SLOT) = *(UINT32 *)&ret[0]; + break; + case FFI_TYPE_SINT32: + *(stack - FIRST_ARG_SLOT) = *(SINT32 *)&ret[0]; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + *(stack - FIRST_ARG_SLOT) = *(UINT32 *)&ret[0]; + *(stack - FIRST_ARG_SLOT - 1) = *(UINT32 *)&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_STRUCT1: + tmp = (void*)(stack - FIRST_ARG_SLOT); + tmp += 4 - cif->rtype->size; + memcpy((void*)tmp, &ret[0], cif->rtype->size); + break; + + case FFI_TYPE_SMALL_STRUCT2: + *(stack - FIRST_ARG_SLOT) = ret[0]; + *(stack - FIRST_ARG_SLOT - 1) = ret[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. */ + +void ffi_closure_LINUX(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); + + FFI_ASSERT (cif->abi == FFI_LINUX); + + /* Make a small trampoline that will branch to our + handler function. Use PC-relative addressing. */ + + 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_LINUX) & ~2); + + /* Flush d/icache -- have to flush up 2 two lines because of + alignment. */ + asm volatile ( + "fdc 0(%0)\n" + "fdc %1(%0)\n" + "fic 0(%%sr4, %0)\n" + "fic %1(%%sr4, %0)\n" + "sync\n" + : : "r"((unsigned long)tramp & ~31), "r"(32 /* stride */)); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} +#endif diff --git a/libffi/src/pa/ffitarget.h b/libffi/src/pa/ffitarget.h new file mode 100644 index 0000000..b8bcad0 --- /dev/null +++ b/libffi/src/pa/ffitarget.h @@ -0,0 +1,57 @@ +/* -----------------------------------------------------------------*-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 + FFI_LINUX, + FFI_DEFAULT_ABI = FFI_LINUX, +#endif + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#define FFI_TRAMPOLINE_SIZE 32 + +#define FFI_TYPE_SMALL_STRUCT1 -1 +#define FFI_TYPE_SMALL_STRUCT2 -2 +#endif + diff --git a/libffi/src/pa/linux.S b/libffi/src/pa/linux.S new file mode 100644 index 0000000..1a2ecdb --- /dev/null +++ b/libffi/src/pa/linux.S @@ -0,0 +1,281 @@ +/* ----------------------------------------------------------------------- + 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 + .align 4 + + /* void ffi_call_LINUX(void (*)(char *, extended_cif *), + extended_cif *ecif, + unsigned bytes, + unsigned flags, + unsigned *rvalue, + void (*fn)()); + */ + + .export ffi_call_LINUX,code + .import ffi_prep_args_LINUX,code + + .type ffi_call_LINUX, @function +.LFB1: +ffi_call_LINUX: + .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_LINUX ] + + [ 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_LINUX,%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. */ + +checksmst1: + comib,<>,n FFI_TYPE_SMALL_STRUCT1, %r21, checksmst2 + /* There is maybe a better way to handle 3 byte structs. */ + sh2add %ret0,0,%ret0 + sh2add %ret0,0,%ret0 + sh2add %ret0,0,%ret0 + sh2add %ret0,0,%ret0 + b done + stw %ret0, 0(%r20) + +checksmst2: + comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, checkint8 + /* Up to now I don't have a way to handle 6/7 byte structs. + The values are left bounded in the registers. In the struct + itself they are left bounded. */ + stw %ret0, 0(%r20) + b done + stw %ret1, 4(%r20) + +checkint8: + comib,<>,n FFI_TYPE_UINT8, %r21, checkint16 + b done + stb %ret0, 0(%r20) + +checkint16: + comib,<>,n FFI_TYPE_UINT16, %r21, checkint32 + b done + sth %ret0, 0(%r20) + +checkint32: + comib,<>,n FFI_TYPE_UINT32, %r21, checkint + b done + stw %ret0, 0(%r20) + +checkint: + comib,<>,n FFI_TYPE_INT, %r21, checkll + b done + stw %ret0, 0(%r20) + +checkll: + comib,<>,n FFI_TYPE_UINT64, %r21, checkdbl + stw %ret0, 0(%r20) + b done + stw %ret1, 4(%r20) + +checkdbl: + comib,<>,n FFI_TYPE_DOUBLE, %r21, checkfloat + b done + fstd %fr4,0(%r20) + +checkfloat: + comib,<>,n FFI_TYPE_FLOAT, %r21, done + fstw %fr4L,0(%r20) + + /* structure returns are either handled by one of the + INT/UINT64 cases above, or, if passed by pointer, + is handled by the callee. */ + +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 +.LFE1: + + /* void ffi_closure_LINUX(void); + Called with closure argument in %r21 */ + .export ffi_closure_LINUX,code + .import ffi_closure_inner_LINUX,code + + .type ffi_closure_LINUX, @function +.LFB2: +ffi_closure_LINUX: + .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_LINUX, %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 .LCFI12-.LCFI11 + .byte 0xd ;# DW_CFA_def_cfa_register = r3 + .uleb128 0x3 + + .align 4 +.LEFDE2: |