ctypes-commit Mailing List for ctypes (Page 29)
Brought to you by:
theller
You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
(8) |
May
(90) |
Jun
(143) |
Jul
(106) |
Aug
(94) |
Sep
(84) |
Oct
(163) |
Nov
(60) |
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(128) |
Feb
(79) |
Mar
(227) |
Apr
(192) |
May
(179) |
Jun
(41) |
Jul
(53) |
Aug
(103) |
Sep
(28) |
Oct
(38) |
Nov
(81) |
Dec
(17) |
2006 |
Jan
(184) |
Feb
(111) |
Mar
(188) |
Apr
(67) |
May
(58) |
Jun
(123) |
Jul
(73) |
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
From: Thomas H. <th...@us...> - 2006-01-31 19:44:53
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582/source/libffi/src Added Files: Tag: branch_1_0 prep_cif.c Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. --- NEW FILE: prep_cif.c --- /* ----------------------------------------------------------------------- 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(/*@out@*/ ffi_type *arg) { ffi_type **ptr; FFI_ASSERT(arg != NULL); /*@-usedef@*/ 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; /*@=usedef@*/ } /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, ffi_abi abi, unsigned int nargs, /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, /*@dependent@*/ 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 */ /*@-usedef@*/ if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) return FFI_BAD_TYPEDEF; /*@=usedef@*/ /* 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 ) 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); } |
From: Thomas H. <th...@us...> - 2006-01-31 19:44:52
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/ia64 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582/source/libffi/src/ia64 Added Files: Tag: branch_1_0 ffi.c ffitarget.h ia64_flags.h unix.S Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. --- NEW FILE: unix.S --- /* ----------------------------------------------------------------------- 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. */ mov out0 = gp add gp = 16, gp ;; 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_int8: .body .copy_state 1 ld1 r8 = [r16] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_int16: .body .copy_state 1 ld2 r8 = [r16] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_int32: .body .copy_state 1 ld4 r8 = [r16] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_int64: .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_int32) // 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_int8) // FFI_TYPE_UINT8 data8 @pcrel(.Lld_int8) // FFI_TYPE_SINT8 data8 @pcrel(.Lld_int16) // FFI_TYPE_UINT16 data8 @pcrel(.Lld_int16) // FFI_TYPE_SINT16 data8 @pcrel(.Lld_int32) // FFI_TYPE_UINT32 data8 @pcrel(.Lld_int32) // FFI_TYPE_SINT32 data8 @pcrel(.Lld_int64) // FFI_TYPE_UINT64 data8 @pcrel(.Lld_int64) // FFI_TYPE_SINT64 data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT data8 @pcrel(.Lld_int64) // 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 --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- 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. */ static inline void stf_spill(fpreg *addr, __float80 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. */ static inline __float80 ldf_fill(fpreg *addr) { __float80 ret; asm ("ldf.fill %0 = %1%P1" : "=f"(ret) : "m"(*addr)); return ret; } /* 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 __float80 hfa_type_load (int type, void *addr) { switch (type) { case FFI_IA64_TYPE_HFA_FLOAT: return *(float *) addr; case FFI_IA64_TYPE_HFA_DOUBLE: return *(double *) addr; case FFI_IA64_TYPE_HFA_LDOUBLE: return *(__float80 *) addr; 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, __float80 value) { switch (type) { case FFI_IA64_TYPE_HFA_FLOAT: *(float *) addr = value; break; case FFI_IA64_TYPE_HFA_DOUBLE: *(double *) addr = value; break; case FFI_IA64_TYPE_HFA_LDOUBLE: *(__float80 *) addr = value; 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) { stf_spill (&stack->fp_regs[fpcount], hfa_type_load (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) { void *addr = &stack->fp_regs[fpcount++]; avalue[i] = addr; *(float *)addr = ldf_fill (addr); } else avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4); gpcount++; break; case FFI_TYPE_DOUBLE: if (gpcount < 8 && fpcount < 8) { void *addr = &stack->fp_regs[fpcount++]; avalue[i] = addr; *(double *)addr = ldf_fill (addr); } 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) { void *addr = &stack->fp_regs[fpcount++]; avalue[i] = addr; *(__float80 *)addr = ldf_fill (addr); } 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, ldf_fill (&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; } --- NEW FILE: ia64_flags.h --- /* ----------------------------------------------------------------------- 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) --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-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 ffi_arg; typedef signed 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 |
From: Thomas H. <th...@us...> - 2006-01-31 19:44:52
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/s390 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582/source/libffi/src/s390 Added Files: Tag: branch_1_0 ffi.c ffitarget.h sysv.S Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. --- NEW FILE: sysv.S --- /* ----------------------------------------------------------------------- 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 --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- 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 ============================*/ --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-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 |
From: Thomas H. <th...@us...> - 2006-01-31 19:44:52
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/x86 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582/source/libffi/src/x86 Added Files: Tag: branch_1_0 ffi.c ffi64.c ffitarget.h sysv.S unix64.S win32.S Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-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 #ifdef X86_64 #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 --- NEW FILE: win32.S --- /* ----------------------------------------------------------------------- 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: --- NEW FILE: ffi64.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2002 Bo Thorsen <bo...@su...> 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)()); /* 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 << 11; } } cif->flags = flags; /* 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; } } 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 == 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); } 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 */ tramp[5] = 0xba49; /* mov <data>, %r10 */ tramp[10] = 0xff49; /* jmp *%r11 */ tramp[11] = 0x00e3; *(void * volatile *) &tramp[1] = ffi_closure_unix64; *(void * volatile *) &tramp[6] = closure; 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__ */ --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- 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 */ /*@-exportheader@*/ void ffi_prep_args(char *stack, extended_cif *ecif) /*@=exportheader@*/ { 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: #ifndef X86_WIN32 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; #ifdef X86_WIN32 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; } return FFI_OK; } /*@-declundef@*/ /*@-exportheader@*/ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); /*@=declundef@*/ /*@=exportheader@*/ #ifdef X86_WIN32 /*@-declundef@*/ /*@-exportheader@*/ extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); /*@=declundef@*/ /*@=exportheader@*/ #endif /* X86_WIN32 */ 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->flags == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #ifdef X86_WIN32 case FFI_STDCALL: /*@-usedef@*/ ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ 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); static void ffi_closure_SYSV (ffi_closure *) __attribute__ ((regparm(1))); static void ffi_closure_raw_SYSV (ffi_raw_closure *) __attribute__ ((regparm(1))); /* This function is jumped to by the trampoline */ static void ffi_closure_SYSV (closure) ffi_closure *closure; { // this is our return value storage long double res; // our various things... ffi_cif *cif; void **arg_area; unsigned short rtype; void *resp = (void*)&res; void *args = __builtin_dwarf_cfa (); 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, (void**)&resp, arg_area, cif); (closure->fun) (cif, resp, arg_area, closure->user_data); rtype = cif->flags; /* now, do a generic return based on the value of rtype */ if (rtype == FFI_TYPE_INT) { asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); } else if (rtype == FFI_TYPE_FLOAT) { asm ("flds (%0)" : : "r" (resp) : "st" ); } else if (rtype == FFI_TYPE_DOUBLE) { asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_LONGDOUBLE) { asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_SINT64) { asm ("movl 0(%0),%%eax;" "movl 4(%0),%%edx" : : "r"(resp) : "eax", "edx"); } #ifdef X86_WIN32 else if (rtype == FFI_TYPE_SINT8) /* 1-byte struct */ { asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax"); } else if (rtype == FFI_TYPE_SINT16) /* 2-bytes struct */ { asm ("movswl (%0),%%eax" : : "r" (resp) : "eax"); } #endif } /*@-exportheader@*/ static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, ffi_cif *cif) /*@=exportheader@*/ { 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 static void ffi_closure_raw_SYSV (closure) ffi_raw_closure *closure; { // this is our return value storage long double res; // our various things... ffi_raw *raw_args; ffi_cif *cif; unsigned short rtype; void *resp = (void*)&res; /* get the cif */ cif = closure->cif; /* the SYSV/X86 abi matches the RAW API exactly, well.. almost */ raw_args = (ffi_raw*) __builtin_dwarf_cfa (); (closure->fun) (cif, resp, raw_args, closure->user_data); rtype = cif->flags; /* now, do a generic return based on the value of rtype */ if (rtype == FFI_TYPE_INT) { asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); } else if (rtype == FFI_TYPE_FLOAT) { asm ("flds (%0)" : : "r" (resp) : "st" ); } else if (rtype == FFI_TYPE_DOUBLE) { asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_LONGDOUBLE) { asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_SINT64) { asm ("movl 0(%0),%%eax; movl 4(%0),%%edx" : : "r"(resp) : "eax", "edx"); } } 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 *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); #ifdef X86_WIN32 extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); #endif /* X86_WIN32 */ void ffi_raw_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ 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)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #ifdef X86_WIN32 case FFI_STDCALL: /*@-usedef@*/ ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #endif /* X86_WIN32 */ default: FFI_ASSERT(0); break; } } #endif #endif /* __x86_64__ */ --- NEW FILE: unix64.S --- /* ----------------------------------------------------------------------- unix64.S - Copyright (c) 2002 Bo Thorsen <bo...@su...> 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. */ /* 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 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 /* 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 11-31 contain the true size of the structure. Copy from the scratch area to the true destination. */ shrl $11, %ecx rep movsb ret .LUW3: .size ffi_call_unix64,.-ffi_call_unix64 .align 2 .globl ffi_closure_unix64 .type ffi_closure_unix64,@function ffi_closure_unix64: .LUW4: subq $200, %rsp .LUW5: movq %rdi, (%rsp) movq %rsi, 8(%rsp) movq %rdx, 16(%rsp) movq %rcx, 24(%rsp) movq %r8, 32(%rsp) movq %r9, 40(%rsp) 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) 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 .LUW6: /* 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 .LUW7: .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 .LUW3-.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 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 */ .align 8 .LEFDE1: .LSFDE3: .long .LEFDE3-.LASFDE3 /* FDE Length */ .LASFDE3: .long .LASFDE3-.Lframe1 /* FDE CIE offset */ .long .LUW4-. /* FDE initial location */ .long .LUW7-.LUW4 /* FDE address range */ .uleb128 0x0 /* Augmentation size */ .byte 0x4 /* DW_CFA_advance_loc4 */ .long .LUW5-.LUW4 .byte 0xe /* DW_CFA_def_cfa_offset */ .uleb128 208 .byte 0x4 /* DW_CFA_advance_loc4 */ .long .LUW6-.LUW5 .byte 0xe /* DW_CFA_def_cfa_offset */ .uleb128 8 .align 8 .LEFDE3: #endif /* __x86_64__ */ --- NEW FILE: sysv.S --- /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 1996, 1998, 2001, 2002, 2003 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 .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: #endif /* ifndef __x86_64__ */ |
From: Thomas H. <th...@us...> - 2006-01-31 19:44:51
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/sparc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582/source/libffi/src/sparc Added Files: Tag: branch_1_0 ffi.c ffitarget.h v8.S v9.S Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. --- NEW FILE: v9.S --- /* ----------------------------------------------------------------------- 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 --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-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 --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- 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; } --- NEW FILE: v8.S --- /* ----------------------------------------------------------------------- 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: |
From: Thomas H. <th...@us...> - 2006-01-31 19:44:51
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/sh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582/source/libffi/src/sh Added Files: Tag: branch_1_0 ffi.c ffitarget.h sysv.S Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. --- NEW FILE: sysv.S --- /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 2002, 2003, 2004 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: 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 r14,@-r15 .LCFI7: sts.l pr,@-r15 /* Stack layout: ... 32 bytes (floating register parameters, SH-4 only) 16 bytes (register parameters) 8 bytes (result) 4 bytes (pad) 4 bytes (5th arg) <- new stack pointer */ .LCFI8: #if defined(__SH4__) add #-64,r15 #else add #-32,r15 #endif .LCFI9: mov r15,r14 .LCFIA: mov r14,r1 add #32,r1 mov.l r7,@-r1 mov.l r6,@-r1 mov.l r5,@-r1 mov.l r4,@-r1 mov r1,r6 #if defined(__SH4__) mov r14,r1 add #64,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 #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 #64,r15 #else add #32,r15 #endif lds.l @r15+,pr rts mov.l @r15+,r14 .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 0x8 */ .byte 0x4 /* DW_CFA_advance_loc4 */ .4byte .LCFI9-.LCFI8 .byte 0xe /* DW_CFA_def_cfa_offset */ #if defined(__SH4__) .byte 8+64 /* uleb128 8+64 */ #else .byte 8+32 /* uleb128 8+32 */ #endif .byte 0x91 /* DW_CFA_offset, column 0x11 */ .byte 0x2 .byte 0x8e /* DW_CFA_offset, column 0xe */ .byte 0x1 .byte 0x4 /* DW_CFA_advance_loc4 */ .4byte .LCFIA-.LCFI9 .byte 0xd /* DW_CFA_def_cfa_register */ .byte 0xe /* uleb128 0xe */ .align 2 .LEFDE3: --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2002, 2003, 2004 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 */ /*@-exportheader@*/ void ffi_prep_args(char *stack, extended_cif *ecif) /*@=exportheader@*/ { 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; greg += n; #else if (greg >= NGREGARG) continue; else if (greg + n - 1 >= NGREGARG) greg = NGREGARG; else greg += n; #endif 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) greg = NGREGARG; else 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; } /*@-declundef@*/ /*@-exportheader@*/ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), /*@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: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; default: FFI_ASSERT(0); break; } } 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; double temp; 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 = *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; 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; greg += n; #else if (greg >= NGREGARG) continue; else if (greg + n - 1 >= NGREGARG) greg = NGREGARG; else greg += n; #endif 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 = 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); } --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-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 |
From: Thomas H. <th...@us...> - 2006-01-31 19:44:51
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/powerpc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582/source/libffi/src/powerpc Added Files: Tag: branch_1_0 aix.S aix_closure.S asm.h darwin.S darwin_closure.S ffi.c ffi_darwin.c ffitarget.h linux64.S linux64_closure.S ppc_closure.S sysv.S Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. --- NEW FILE: aix.S --- /* ----------------------------------------------------------------------- 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) --- NEW FILE: ffi_darwin.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998 Geoffrey Keating PowerPC Foreign Function Interface Darwin ABI support (c) 2001 John Hornkvist AIX ABI support (c) 2002 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 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 */ /*@-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 + (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); } /* 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. Redo the calculation for DARWIN. */ /* 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; } /*@-declundef@*/ /*@-exportheader@*/ extern void ffi_call_AIX(/*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)(), void (*fn2)()); extern void ffi_call_DARWIN(/*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)(), void (*fn2)()); /*@=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_AIX: /*@-usedef@*/ ffi_call_AIX(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn, ffi_prep_args); /*@=usedef@*/ break; case FFI_DARWIN: /*@-usedef@*/ ffi_call_DARWIN(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn, ffi_prep_args); /*@=usedef@*/ 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; } --- NEW FILE: asm.h --- /* ----------------------------------------------------------------------- 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 --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-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, # ifdef POWERPC64 FFI_DEFAULT_ABI = FFI_LINUX64, # else FFI_DEFAULT_ABI = FFI_GCC_SYSV, # 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 FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #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 --- NEW FILE: aix_closure.S --- /* ----------------------------------------------------------------------- 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) */ --- NEW FILE: linux64.S --- /* ----------------------------------------------------------------------- sysv.h - Copyright (c) 2003 Jakub Jelinek <ja...@re...> 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) stfd %f2, 8(%r30) /* It might be a long double */ 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 --- NEW FILE: darwin.S --- /* ----------------------------------------------------------------------- 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. ----------------------------------------------------------------------- */ #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 2 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 .long LLFB0$non_lazy_ptr-. ; FDE initial location .set L$set$3,LFE1-LFB0 .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 2 LEFDE1: .data .align 2 LLFB0$non_lazy_ptr: .long LFB0 --- NEW FILE: linux64_closure.S --- #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> .file "linux64_closure.S" #ifdef __powerpc64__ .hidden ffi_closure_LINUX64, .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 --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998 Geoffrey Keating PowerPC 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. [...1098 lines suppressed...] } avalue[i] = pst; } pst += 2; break; #endif default: FFI_ASSERT(0); } i++; } (closure->fun) (cif, rvalue, avalue, closure->user_data); /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ return cif->rtype->type; } --- NEW FILE: ppc_closure.S --- #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 JUMPTARGET(ffi_closure_helper_SYSV) # now r3 contains the return type # so use it to look up in a table # so we know how to deal with each type # look up the proper starting point in table # by using return type as offset addi %r5,%r1,112 # get pointer to results area 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) b .Lfinish nop 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: lwz %r0,148(%r1) 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 __... [truncated message content] |
From: Thomas H. <th...@us...> - 2006-01-31 19:44:47
|
Update of /cvsroot/ctypes/ctypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14582 Modified Files: Tag: branch_1_0 setup.py Log Message: Integrated a patch from Hye-Shik Chang (perky). He wrote (http://mail.python.org/pipermail/python-dev/2006-January/060199.html): I did some work to make ctypes+libffi compacter and liberal. http://openlook.org/svnpublic/ctypes-compactffi/ (snv) I removed sources/gcc and put sources/libffi copied from gcc 4.0.2. And removed all automake-related build processes and integrated them info setup.py. There's still aclocal.m4 in sources/libffi. But it is just identical to libffi's acinclude.m4 which looks liberal. Index: setup.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/setup.py,v retrieving revision 1.122.2.10 retrieving revision 1.122.2.11 diff -C2 -d -r1.122.2.10 -r1.122.2.11 *** setup.py 2 Jan 2006 19:07:50 -0000 1.122.2.10 --- setup.py 31 Jan 2006 19:44:35 -0000 1.122.2.11 *************** *** 10,14 **** """ ! LIBFFI_SOURCES='source/gcc/libffi' __version__ = "0.9.9.1" --- 10,14 ---- """ ! LIBFFI_SOURCES='source/libffi' __version__ = "0.9.9.1" *************** *** 123,150 **** build_ext.build_ext.finalize_options(self) ! # First build a static libffi library, then build the _ctypes extension. ! def run(self): ! self.build_libffi_static() ! build_ext.build_ext.run(self) ! def fix_extension(self, inst_dir): ! incdir = find_file_in_subdir(os.path.join(inst_dir, "include"), "ffi.h") ! if not incdir: return 0 ! libdir = find_file_in_subdir(os.path.join(inst_dir, "lib"), "libffi.a") or \ ! find_file_in_subdir(os.path.join(inst_dir, "lib64"), "libffi.a") ! if not libdir: return 0 ! incdir_2 = find_file_in_subdir(os.path.join(inst_dir, "lib"), "ffitarget.h") if not incdir_2: return 0 for ext in self.extensions: if ext.name == "_ctypes": ext.include_dirs.append(incdir) ext.include_dirs.append(incdir_2) ! ext.library_dirs.append(libdir) return 1 ! def build_libffi_static(self): if sys.platform == "win32": return --- 123,161 ---- build_ext.build_ext.finalize_options(self) ! # First configure a libffi library, then build the _ctypes extension. ! def build_extensions(self): ! self.configure_libffi() ! # Add .S (preprocessed assembly) to C compiler source extensions. ! self.compiler.src_extensions.append('.S') ! ! build_ext.build_ext.build_extensions(self) ! ! def fix_extension(self, ffi_dir): ! fficonfigfile = os.path.join(ffi_dir, 'fficonfig.py') ! if not os.path.exists(fficonfigfile): return 0 ! ! incdir = find_file_in_subdir(os.path.join(ffi_dir, "include"), "ffi.h") ! if not incdir: return 0 ! incdir_2 = find_file_in_subdir(ffi_dir, "fficonfig.h") if not incdir_2: return 0 + + fficonfig = {} + execfile(fficonfigfile, globals(), fficonfig) + for ext in self.extensions: if ext.name == "_ctypes": ext.include_dirs.append(incdir) ext.include_dirs.append(incdir_2) ! ext.sources.extend(fficonfig['ffi_sources']) ! if fficonfig['ffi_cflags'].strip(): ! ext.extra_compile_args.extend( ! fficonfig['ffi_cflags'].split()) return 1 ! def configure_libffi(self): if sys.platform == "win32": return *************** *** 157,187 **** build_dir = os.path.join(self.build_temp, 'libffi') - inst_dir = os.path.abspath(self.build_temp) ! if not self.force and self.fix_extension(inst_dir): return mkpath(build_dir) ! config_args = ["--disable-shared", ! "--enable-static", ! "--enable-multilib=no", ! "--prefix='%s'" % inst_dir, ! ] ! cmd = "cd %s && '%s/configure' %s && make install" \ % (build_dir, src_dir, " ".join(config_args)) ! print 'Building static FFI library:' print cmd - if sys.platform == "openbsd3": - os.environ["CFLAGS"] = "-fno-stack-protector" res = os.system(cmd) - if sys.platform == "openbsd3": - del os.environ["CFLAGS"] if res: print "Failed" sys.exit(res) ! assert self.fix_extension(inst_dir), "Could not find libffi after building it" # Since we mangle the build_temp dir, we must also do this in the clean command. --- 168,191 ---- build_dir = os.path.join(self.build_temp, 'libffi') ! if not self.force and self.fix_extension(build_dir): return mkpath(build_dir) ! config_args = [] ! # Pass empty CFLAGS because we'll just append the resulting CFLAGS ! # to Python's; -g or -O2 is to be avoided. ! cmd = "cd %s && env CFLAGS='' '%s/configure' %s" \ % (build_dir, src_dir, " ".join(config_args)) ! print 'Configuring static FFI library:' print cmd res = os.system(cmd) if res: print "Failed" sys.exit(res) ! assert self.fix_extension(build_dir), "Could not find libffi after building it" # Since we mangle the build_temp dir, we must also do this in the clean command. *************** *** 255,259 **** extensions = [Extension("_ctypes", - libraries=["ffi"], include_dirs=include_dirs, library_dirs=library_dirs, --- 259,262 ---- |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:09
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/powerpc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/powerpc Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/powerpc added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:09
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/pa In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/pa Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/pa added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:09
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/m32r In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/m32r Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/m32r added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:09
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/ia64 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/ia64 Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/ia64 added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:08
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/sh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/sh Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/sh added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:05
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/s390 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/s390 Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/s390 added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:02
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/sparc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/sparc Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/sparc added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:02
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/x86 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/x86 Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/x86 added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:00
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/m68k In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/m68k Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/m68k added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:00
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/alpha In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/alpha Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/alpha added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:36:00
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/arm In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/arm Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/arm added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:35:59
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/frv In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/frv Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/frv added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:35:59
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/mips In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/mips Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/mips added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:35:58
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/sh64 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11143/source/libffi/src/sh64 Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src/sh64 added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:35:33
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10921/source/libffi/src Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/src added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:35:29
|
Update of /cvsroot/ctypes/ctypes/source/libffi/include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10921/source/libffi/include Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi/include added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2006-01-31 19:35:09
|
Update of /cvsroot/ctypes/ctypes/source/libffi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10660/source/libffi Log Message: Directory /cvsroot/ctypes/ctypes/source/libffi added to the repository --> Using per-directory sticky tag `branch_1_0' |