diff options
author | Christian Heimes <christian@cheimes.de> | 2008-03-04 23:39:23 (GMT) |
---|---|---|
committer | Christian Heimes <christian@cheimes.de> | 2008-03-04 23:39:23 (GMT) |
commit | 7864476afa402a0537c33ba9630e77351720baf8 (patch) | |
tree | cb9113e14d6a0b56696398f4d61d107ea7055e08 /Modules/_ctypes/libffi_osx | |
parent | 227c800f4397764a20b77fd58467e2bb27fbf510 (diff) | |
download | cpython-7864476afa402a0537c33ba9630e77351720baf8.zip cpython-7864476afa402a0537c33ba9630e77351720baf8.tar.gz cpython-7864476afa402a0537c33ba9630e77351720baf8.tar.bz2 |
Merged revisions 61209-61214,61217-61222,61224-61226,61233-61237 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r61209 | georg.brandl | 2008-03-03 21:37:55 +0100 (Mon, 03 Mar 2008) | 2 lines
There are now sixteen isfoo functions.
........
r61210 | georg.brandl | 2008-03-03 21:39:00 +0100 (Mon, 03 Mar 2008) | 2 lines
15 -> 16, the 2nd
........
r61211 | georg.brandl | 2008-03-03 22:22:47 +0100 (Mon, 03 Mar 2008) | 2 lines
Actually import itertools.
........
r61212 | georg.brandl | 2008-03-03 22:31:50 +0100 (Mon, 03 Mar 2008) | 2 lines
Expand a bit on genexp scopes.
........
r61213 | raymond.hettinger | 2008-03-03 23:04:55 +0100 (Mon, 03 Mar 2008) | 1 line
Remove dependency on itertools -- a simple genexp suffices.
........
r61214 | raymond.hettinger | 2008-03-03 23:19:58 +0100 (Mon, 03 Mar 2008) | 1 line
Issue 2226: Callable checked for the wrong abstract method.
........
r61217 | andrew.kuchling | 2008-03-04 01:40:32 +0100 (Tue, 04 Mar 2008) | 1 line
Typo fix
........
r61218 | andrew.kuchling | 2008-03-04 02:30:10 +0100 (Tue, 04 Mar 2008) | 1 line
Grammar fix; markup fix
........
r61219 | andrew.kuchling | 2008-03-04 02:47:38 +0100 (Tue, 04 Mar 2008) | 1 line
Fix sentence fragment
........
r61220 | andrew.kuchling | 2008-03-04 02:48:26 +0100 (Tue, 04 Mar 2008) | 1 line
Typo fix
........
r61221 | andrew.kuchling | 2008-03-04 02:49:37 +0100 (Tue, 04 Mar 2008) | 1 line
Add versionadded tags
........
r61222 | andrew.kuchling | 2008-03-04 02:50:32 +0100 (Tue, 04 Mar 2008) | 1 line
Thesis night results: add various items
........
r61224 | raymond.hettinger | 2008-03-04 05:17:08 +0100 (Tue, 04 Mar 2008) | 1 line
Beef-up docs and tests for itertools. Fix-up end-case for product().
........
r61225 | georg.brandl | 2008-03-04 08:25:54 +0100 (Tue, 04 Mar 2008) | 2 lines
Fix some patch attributions.
........
r61226 | georg.brandl | 2008-03-04 08:33:30 +0100 (Tue, 04 Mar 2008) | 2 lines
#2230: document that PyArg_* leaves addresses alone on error.
........
r61233 | neal.norwitz | 2008-03-04 17:22:46 +0100 (Tue, 04 Mar 2008) | 3 lines
Close the file before trying to remove the directory so it works on Windows.
As reported by Trent Nelson on python-dev.
........
r61234 | thomas.heller | 2008-03-04 21:09:11 +0100 (Tue, 04 Mar 2008) | 9 lines
Merged changes from libffi3-branch.
The bundled libffi copy is now in sync with the recently released
libffi3.0.4 version, apart from some small changes to
Modules/_ctypes/libffi/configure.ac.
I gave up on using libffi3 files on os x.
Instead, static configuration with files from pyobjc is used.
........
r61235 | thomas.heller | 2008-03-04 21:21:42 +0100 (Tue, 04 Mar 2008) | 1 line
Try to fix the build for PY_LINUX.
........
r61236 | fred.drake | 2008-03-04 22:14:04 +0100 (Tue, 04 Mar 2008) | 2 lines
fix typo
........
r61237 | raymond.hettinger | 2008-03-04 23:29:44 +0100 (Tue, 04 Mar 2008) | 1 line
Fix refleak in chain().
........
Diffstat (limited to 'Modules/_ctypes/libffi_osx')
20 files changed, 6524 insertions, 0 deletions
diff --git a/Modules/_ctypes/libffi_osx/LICENSE b/Modules/_ctypes/libffi_osx/LICENSE new file mode 100644 index 0000000..f591795 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/LICENSE @@ -0,0 +1,20 @@ +libffi - Copyright (c) 1996-2003 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. diff --git a/Modules/_ctypes/libffi_osx/README b/Modules/_ctypes/libffi_osx/README new file mode 100644 index 0000000..1fc2747 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/README @@ -0,0 +1,500 @@ +This directory contains the libffi package, which is not part of GCC but +shipped with GCC as convenience. + +Status +====== + +libffi-2.00 has not been released yet! This is a development snapshot! + +libffi-1.20 was released on October 5, 1998. Check the libffi web +page for updates: <URL:http://sources.redhat.com/libffi/>. + + +What is libffi? +=============== + +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the "calling +convention". The "calling convention" is essentially a set of +assumptions made by the compiler about where function arguments will +be found on entry to a function. A "calling convention" also specifies +where the return value for a function is found. + +Some programs may not know at the time of compilation what arguments +are to be passed to a function. For instance, an interpreter may be +told at run-time about the number and types of arguments used to call +a given function. Libffi can be used in such programs to provide a +bridge from the interpreter program to compiled code. + +The libffi library provides a portable, high level programming +interface to various calling conventions. This allows a programmer to +call any function specified by a call interface description at run +time. + +Ffi stands for Foreign Function Interface. A foreign function +interface is the popular name for the interface that allows code +written in one language to call code written in another language. The +libffi library really only provides the lowest, machine dependent +layer of a fully featured foreign function interface. A layer must +exist above libffi that handles type conversions for values passed +between the two languages. + + +Supported Platforms and Prerequisites +===================================== + +Libffi has been ported to: + + SunOS 4.1.3 & Solaris 2.x (SPARC-V8, SPARC-V9) + + Irix 5.3 & 6.2 (System V/o32 & n32) + + Intel x86 - Linux (System V ABI) + + Alpha - Linux and OSF/1 + + m68k - Linux (System V ABI) + + PowerPC - Linux (System V ABI, Darwin, AIX) + + ARM - Linux (System V ABI) + +Libffi has been tested with the egcs 1.0.2 gcc compiler. Chances are +that other versions will work. Libffi has also been built and tested +with the SGI compiler tools. + +On PowerPC, the tests failed (see the note below). + +You must use GNU make to build libffi. SGI's make will not work. +Sun's probably won't either. + +If you port libffi to another platform, please let me know! I assume +that some will be easy (x86 NetBSD), and others will be more difficult +(HP). + + +Installing libffi +================= + +[Note: before actually performing any of these installation steps, + you may wish to read the "Platform Specific Notes" below.] + +First you must configure the distribution for your particular +system. Go to the directory you wish to build libffi in and run the +"configure" program found in the root directory of the libffi source +distribution. + +You may want to tell configure where to install the libffi library and +header files. To do that, use the --prefix configure switch. Libffi +will install under /usr/local by default. + +If you want to enable extra run-time debugging checks use the the +--enable-debug configure switch. This is useful when your program dies +mysteriously while using libffi. + +Another useful configure switch is --enable-purify-safety. Using this +will add some extra code which will suppress certain warnings when you +are using Purify with libffi. Only use this switch when using +Purify, as it will slow down the library. + +Configure has many other options. Use "configure --help" to see them all. + +Once configure has finished, type "make". Note that you must be using +GNU make. SGI's make will not work. Sun's probably won't either. +You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. + +To ensure that libffi is working as advertised, type "make test". + +To install the library and header files, type "make install". + + +Using libffi +============ + + The Basics + ---------- + +Libffi assumes that you have a pointer to the function you wish to +call and that you know the number and types of arguments to pass it, +as well as the return type of the function. + +The first thing you must do is create an ffi_cif object that matches +the signature of the function you wish to call. The cif in ffi_cif +stands for Call InterFace. To prepare a call interface object, use the +following function: + +ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, + unsigned int nargs, + ffi_type *rtype, ffi_type **atypes); + + CIF is a pointer to the call interface object you wish + to initialize. + + ABI is an enum that specifies the calling convention + to use for the call. FFI_DEFAULT_ABI defaults + to the system's native calling convention. Other + ABI's may be used with care. They are system + specific. + + NARGS is the number of arguments this function accepts. + libffi does not yet support vararg functions. + + RTYPE is a pointer to an ffi_type structure that represents + the return type of the function. Ffi_type objects + describe the types of values. libffi provides + ffi_type objects for many of the native C types: + signed int, unsigned int, signed char, unsigned char, + etc. There is also a pointer ffi_type object and + a void ffi_type. Use &ffi_type_void for functions that + don't return values. + + ATYPES is a vector of ffi_type pointers. ARGS must be NARGS long. + If NARGS is 0, this is ignored. + + +ffi_prep_cif will return a status code that you are responsible +for checking. It will be one of the following: + + FFI_OK - All is good. + + FFI_BAD_TYPEDEF - One of the ffi_type objects that ffi_prep_cif + came across is bad. + + +Before making the call, the VALUES vector should be initialized +with pointers to the appropriate argument values. + +To call the the function using the initialized ffi_cif, use the +ffi_call function: + +void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues); + + CIF is a pointer to the ffi_cif initialized specifically + for this function. + + FN is a pointer to the function you want to call. + + RVALUE is a pointer to a chunk of memory that is to hold the + result of the function call. Currently, it must be + at least one word in size (except for the n32 version + under Irix 6.x, which must be a pointer to an 8 byte + aligned value (a long long). It must also be at least + word aligned (depending on the return type, and the + system's alignment requirements). If RTYPE is + &ffi_type_void, this is ignored. If RVALUE is NULL, + the return value is discarded. + + AVALUES is a vector of void* that point to the memory locations + holding the argument values for a call. + If NARGS is 0, this is ignored. + + +If you are expecting a return value from FN it will have been stored +at RVALUE. + + + + An Example + ---------- + +Here is a trivial example that calls puts() a few times. + + #include <stdio.h> + #include <ffi.h> + + int main() + { + ffi_cif cif; + ffi_type *args[1]; + void *values[1]; + char *s; + int rc; + + /* Initialize the argument info vectors */ + args[0] = &ffi_type_uint; + values[0] = &s; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, args) == FFI_OK) + { + s = "Hello World!"; + ffi_call(&cif, puts, &rc, values); + /* rc now holds the result of the call to puts */ + + /* values holds a pointer to the function's arg, so to + call puts() again all we need to do is change the + value of s */ + s = "This is cool!"; + ffi_call(&cif, puts, &rc, values); + } + + return 0; + } + + + + Aggregate Types + --------------- + +Although libffi has no special support for unions or bit-fields, it is +perfectly happy passing structures back and forth. You must first +describe the structure to libffi by creating a new ffi_type object +for it. Here is the definition of ffi_type: + + typedef struct _ffi_type + { + unsigned size; + short alignment; + short type; + struct _ffi_type **elements; + } ffi_type; + +All structures must have type set to FFI_TYPE_STRUCT. You may set +size and alignment to 0. These will be calculated and reset to the +appropriate values by ffi_prep_cif(). + +elements is a NULL terminated array of pointers to ffi_type objects +that describe the type of the structure elements. These may, in turn, +be structure elements. + +The following example initializes a ffi_type object representing the +tm struct from Linux's time.h: + + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + /* Those are for future use. */ + long int __tm_gmtoff__; + __const char *__tm_zone__; + }; + + { + ffi_type tm_type; + ffi_type *tm_type_elements[12]; + int i; + + tm_type.size = tm_type.alignment = 0; + tm_type.elements = &tm_type_elements; + + for (i = 0; i < 9; i++) + tm_type_elements[i] = &ffi_type_sint; + + tm_type_elements[9] = &ffi_type_slong; + tm_type_elements[10] = &ffi_type_pointer; + tm_type_elements[11] = NULL; + + /* tm_type can now be used to represent tm argument types and + return types for ffi_prep_cif() */ + } + + + +Platform Specific Notes +======================= + + Intel x86 + --------- + +There are no known problems with the x86 port. + + Sun SPARC - SunOS 4.1.3 & Solaris 2.x + ------------------------------------- + +You must use GNU Make to build libffi on Sun platforms. + + MIPS - Irix 5.3 & 6.x + --------------------- + +Irix 6.2 and better supports three different calling conventions: o32, +n32 and n64. Currently, libffi only supports both o32 and n32 under +Irix 6.x, but only o32 under Irix 5.3. Libffi will automatically be +configured for whichever calling convention it was built for. + +By default, the configure script will try to build libffi with the GNU +development tools. To build libffi with the SGI development tools, set +the environment variable CC to either "cc -32" or "cc -n32" before +running configure under Irix 6.x (depending on whether you want an o32 +or n32 library), or just "cc" for Irix 5.3. + +With the n32 calling convention, when returning structures smaller +than 16 bytes, be sure to provide an RVALUE that is 8 byte aligned. +Here's one way of forcing this: + + double struct_storage[2]; + my_small_struct *s = (my_small_struct *) struct_storage; + /* Use s for RVALUE */ + +If you don't do this you are liable to get spurious bus errors. + +"long long" values are not supported yet. + +You must use GNU Make to build libffi on SGI platforms. + + ARM - System V ABI + ------------------ + +The ARM port was performed on a NetWinder running ARM Linux ELF +(2.0.31) and gcc 2.8.1. + + + + PowerPC System V ABI + -------------------- + +There are two `System V ABI's which libffi implements for PowerPC. +They differ only in how small structures are returned from functions. + +In the FFI_SYSV version, structures that are 8 bytes or smaller are +returned in registers. This is what GCC does when it is configured +for solaris, and is what the System V ABI I have (dated September +1995) says. + +In the FFI_GCC_SYSV version, all structures are returned the same way: +by passing a pointer as the first argument to the function. This is +what GCC does when it is configured for linux or a generic sysv +target. + +EGCS 1.0.1 (and probably other versions of EGCS/GCC) also has a +inconsistency with the SysV ABI: When a procedure is called with many +floating-point arguments, some of them get put on the stack. They are +all supposed to be stored in double-precision format, even if they are +only single-precision, but EGCS stores single-precision arguments as +single-precision anyway. This causes one test to fail (the `many +arguments' test). + + +What's With The Crazy Comments? +=============================== + +You might notice a number of cryptic comments in the code, delimited +by /*@ and @*/. These are annotations read by the program LCLint, a +tool for statically checking C programs. You can read all about it at +<http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>. + + +History +======= + +1.20 Oct-5-98 + Raffaele Sena produces ARM port. + +1.19 Oct-5-98 + Fixed x86 long double and long long return support. + m68k bug fixes from Andreas Schwab. + Patch for DU assembler compatibility for the Alpha from Richard + Henderson. + +1.18 Apr-17-98 + Bug fixes and MIPS configuration changes. + +1.17 Feb-24-98 + Bug fixes and m68k port from Andreas Schwab. PowerPC port from + Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes. + +1.16 Feb-11-98 + Richard Henderson produces Alpha port. + +1.15 Dec-4-97 + Fixed an n32 ABI bug. New libtool, auto* support. + +1.14 May-13-97 + libtool is now used to generate shared and static libraries. + Fixed a minor portability problem reported by Russ McManus + <mcmanr@eq.gs.com>. + +1.13 Dec-2-96 + Added --enable-purify-safety to keep Purify from complaining + about certain low level code. + Sparc fix for calling functions with < 6 args. + Linux x86 a.out fix. + +1.12 Nov-22-96 + Added missing ffi_type_void, needed for supporting void return + types. Fixed test case for non MIPS machines. Cygnus Support + is now Cygnus Solutions. + +1.11 Oct-30-96 + Added notes about GNU make. + +1.10 Oct-29-96 + Added configuration fix for non GNU compilers. + +1.09 Oct-29-96 + Added --enable-debug configure switch. Clean-ups based on LCLint + feedback. ffi_mips.h is always installed. Many configuration + fixes. Fixed ffitest.c for sparc builds. + +1.08 Oct-15-96 + Fixed n32 problem. Many clean-ups. + +1.07 Oct-14-96 + Gordon Irlam rewrites v8.S again. Bug fixes. + +1.06 Oct-14-96 + Gordon Irlam improved the sparc port. + +1.05 Oct-14-96 + Interface changes based on feedback. + +1.04 Oct-11-96 + Sparc port complete (modulo struct passing bug). + +1.03 Oct-10-96 + Passing struct args, and returning struct values works for + all architectures/calling conventions. Expanded tests. + +1.02 Oct-9-96 + Added SGI n32 support. Fixed bugs in both o32 and Linux support. + Added "make test". + +1.01 Oct-8-96 + Fixed float passing bug in mips version. Restructured some + of the code. Builds cleanly with SGI tools. + +1.00 Oct-7-96 + First release. No public announcement. + + +Authors & Credits +================= + +libffi was written by Anthony Green <green@cygnus.com>. + +Portions of libffi were derived from Gianni Mariani's free gencall +library for Silicon Graphics machines. + +The closure mechanism was designed and implemented by Kresten Krab +Thorup. + +The Sparc port was derived from code contributed by the fine folks at +Visible Decisions Inc <http://www.vdi.com>. Further enhancements were +made by Gordon Irlam at Cygnus Solutions <http://www.cygnus.com>. + +The Alpha port was written by Richard Henderson at Cygnus Solutions. + +Andreas Schwab ported libffi to m68k Linux and provided a number of +bug fixes. + +Geoffrey Keating ported libffi to the PowerPC. + +Raffaele Sena ported libffi to the ARM. + +Jesper Skov and Andrew Haley both did more than their fair share of +stepping through the code and tracking down bugs. + +Thanks also to Tom Tromey for bug fixes and configuration help. + +Thanks to Jim Blandy, who provided some useful feedback on the libffi +interface. + +If you have a problem, or have found a bug, please send a note to +green@cygnus.com. diff --git a/Modules/_ctypes/libffi_osx/README.pyobjc b/Modules/_ctypes/libffi_osx/README.pyobjc new file mode 100644 index 0000000..405d85f --- /dev/null +++ b/Modules/_ctypes/libffi_osx/README.pyobjc @@ -0,0 +1,5 @@ +This directory contains a slightly modified version of libffi, extracted from +the GCC source-tree. + +The only modifications are those that are necessary to compile libffi using +the Apple provided compiler and outside of the GCC source tree. diff --git a/Modules/_ctypes/libffi_osx/ffi.c b/Modules/_ctypes/libffi_osx/ffi.c new file mode 100644 index 0000000..bf42093 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/ffi.c @@ -0,0 +1,226 @@ +/* ----------------------------------------------------------------------- + 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 <stdbool.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) +{ +/*@-usedef@*/ + + if (arg == NULL || arg->elements == NULL || + arg->size != 0 || arg->alignment != 0) + return FFI_BAD_TYPEDEF; + + ffi_type** 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); + +#ifdef POWERPC_DARWIN + int curalign = (*ptr)->alignment; + + if (ptr != &(arg->elements[0])) + { + if (curalign > 4 && curalign != 16) + curalign = 4; + } + + arg->size = ALIGN(arg->size, curalign); + arg->size += (*ptr)->size; + arg->alignment = (arg->alignment > curalign) ? + arg->alignment : curalign; +#else + arg->size = ALIGN(arg->size, (*ptr)->alignment); + arg->size += (*ptr)->size; + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; +#endif + + 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; + + return FFI_OK; + +/*@=usedef@*/ +} + +#ifndef __CRIS__ +/* The CRIS ABI specifies structure elements to have byte + alignment only, so it completely overrides this functions, + which assumes "natural" alignment and padding. */ + +/* Perform machine independent ffi_cif preparation, then call + machine dependent routine. */ + +#if defined(X86_DARWIN) + +static inline bool +struct_on_stack( + int size) +{ + if (size > 8) + return true; + + /* This is not what the ABI says, but is what is really implemented */ + switch (size) + { + case 1: + case 2: + case 4: + case 8: + return false; + + default: + return true; + } +} + +#endif // defined(X86_DARWIN) + +// Arguments' ffi_type->alignment must be nonzero. +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) +{ + if (cif == NULL) + return FFI_BAD_TYPEDEF; + + if (abi <= FFI_FIRST_ABI || abi > FFI_DEFAULT_ABI) + return FFI_BAD_ABI; + + unsigned int bytes = 0; + unsigned int i; + ffi_type** ptr; + + 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 +#ifdef X86_DARWIN + && (struct_on_stack(cif->rtype->size)) +#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; + + if ((*ptr)->alignment == 0) + 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_DARWIN) + { + int align = (*ptr)->alignment; + + if (align > 4) + align = 4; + + if ((align - 1) & bytes) + bytes = ALIGN(bytes, align); + + bytes += STACK_ARG_SIZE((*ptr)->size); + } +#elif !defined __x86_64__ && !defined S390 && !defined PA +#ifdef SPARC + if (((*ptr)->type == FFI_TYPE_STRUCT + && ((*ptr)->size > 16 || cif->abi != FFI_V9)) + || ((*ptr)->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_V9)) + bytes += sizeof(void*); + else +#endif + { + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + + bytes += STACK_ARG_SIZE((*ptr)->size); + } +#endif + } + + cif->bytes = bytes; + + /* Perform machine dependent cif processing */ + return ffi_prep_cif_machdep(cif); +} +#endif /* not __CRIS__ */ diff --git a/Modules/_ctypes/libffi_osx/include/ffi.h b/Modules/_ctypes/libffi_osx/include/ffi.h new file mode 100644 index 0000000..3d39064 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/include/ffi.h @@ -0,0 +1,352 @@ +/* -----------------------------------------------------------------*-C-*- + libffi PyOBJC - Copyright (c) 1996-2003 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. + + ----------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------- + The basic API is described in the README file. + + The raw API is designed to bypass some of the argument packing + and unpacking on architectures for which it can be avoided. + + The closure API allows interpreted functions to be packaged up + inside a C function pointer, so that they can be called as C functions, + with no understanding on the client side that they are interpreted. + It can also be used in other cases in which it is necessary to package + up a user specified parameter and a function pointer as a single + function pointer. + + The closure API must be implemented in order to get its functionality, + e.g. for use by gij. Routines are provided to emulate the raw API + if the underlying platform doesn't allow faster implementation. + + More details on the raw and closure API can be found in: + + http://gcc.gnu.org/ml/java/1999-q3/msg00138.html + + and + + http://gcc.gnu.org/ml/java/1999-q3/msg00174.html + -------------------------------------------------------------------- */ + +#ifndef LIBFFI_H +#define LIBFFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Specify which architecture libffi is configured for. */ +#ifdef MACOSX +# if defined(__i386__) || defined(__x86_64__) +# define X86_DARWIN +# elif defined(__ppc__) || defined(__ppc64__) +# define POWERPC_DARWIN +# else +# error "Unsupported MacOS X CPU type" +# endif +#else +#error "Unsupported OS type" +#endif + +/* ---- System configuration information --------------------------------- */ + +#include "ffitarget.h" +#include "fficonfig.h" + +#ifndef LIBFFI_ASM + +#include <stddef.h> +#include <limits.h> + +/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). + But we can find it either under the correct ANSI name, or under GNU + C's internal name. */ +#ifdef LONG_LONG_MAX +# define FFI_LONG_LONG_MAX LONG_LONG_MAX +#else +# ifdef LLONG_MAX +# define FFI_LONG_LONG_MAX LLONG_MAX +# else +# ifdef __GNUC__ +# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ +# endif +# endif +#endif + +#if SCHAR_MAX == 127 +# define ffi_type_uchar ffi_type_uint8 +# define ffi_type_schar ffi_type_sint8 +#else +#error "char size not supported" +#endif + +#if SHRT_MAX == 32767 +# define ffi_type_ushort ffi_type_uint16 +# define ffi_type_sshort ffi_type_sint16 +#elif SHRT_MAX == 2147483647 +# define ffi_type_ushort ffi_type_uint32 +# define ffi_type_sshort ffi_type_sint32 +#else +#error "short size not supported" +#endif + +#if INT_MAX == 32767 +# define ffi_type_uint ffi_type_uint16 +# define ffi_type_sint ffi_type_sint16 +#elif INT_MAX == 2147483647 +# define ffi_type_uint ffi_type_uint32 +# define ffi_type_sint ffi_type_sint32 +#elif INT_MAX == 9223372036854775807 +# define ffi_type_uint ffi_type_uint64 +# define ffi_type_sint ffi_type_sint64 +#else +#error "int size not supported" +#endif + +#define ffi_type_ulong ffi_type_uint64 +#define ffi_type_slong ffi_type_sint64 + +#if LONG_MAX == 2147483647 +# if FFI_LONG_LONG_MAX != 9223372036854775807 +# error "no 64-bit data type supported" +# endif +#elif LONG_MAX != 9223372036854775807 +#error "long size not supported" +#endif + +/* The closure code assumes that this works on pointers, i.e. a size_t + can hold a pointer. */ + +typedef struct _ffi_type { + size_t size; + unsigned short alignment; + unsigned short type; +/*@null@*/ struct _ffi_type** elements; +} ffi_type; + +/* These are defined in types.c */ +extern ffi_type ffi_type_void; +extern ffi_type ffi_type_uint8; +extern ffi_type ffi_type_sint8; +extern ffi_type ffi_type_uint16; +extern ffi_type ffi_type_sint16; +extern ffi_type ffi_type_uint32; +extern ffi_type ffi_type_sint32; +extern ffi_type ffi_type_uint64; +extern ffi_type ffi_type_sint64; +extern ffi_type ffi_type_float; +extern ffi_type ffi_type_double; +extern ffi_type ffi_type_longdouble; +extern ffi_type ffi_type_pointer; + +typedef enum ffi_status { + FFI_OK = 0, + FFI_BAD_TYPEDEF, + FFI_BAD_ABI +} ffi_status; + +typedef unsigned FFI_TYPE; + +typedef struct ffi_cif { + ffi_abi abi; + unsigned nargs; +/*@dependent@*/ ffi_type** arg_types; +/*@dependent@*/ ffi_type* rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; + +/* ---- Definitions for the raw API -------------------------------------- */ + +#ifndef FFI_SIZEOF_ARG +# if LONG_MAX == 2147483647 +# define FFI_SIZEOF_ARG 4 +# elif LONG_MAX == 9223372036854775807 +# define FFI_SIZEOF_ARG 8 +# endif +#endif + +typedef union { + ffi_sarg sint; + ffi_arg uint; + float flt; + char data[FFI_SIZEOF_ARG]; + void* ptr; +} ffi_raw; + +void +ffi_raw_call( +/*@dependent@*/ ffi_cif* cif, + void (*fn)(void), +/*@out@*/ void* rvalue, +/*@dependent@*/ ffi_raw* avalue); + +void +ffi_ptrarray_to_raw( + ffi_cif* cif, + void** args, + ffi_raw* raw); + +void +ffi_raw_to_ptrarray( + ffi_cif* cif, + ffi_raw* raw, + void** args); + +size_t +ffi_raw_size( + ffi_cif* cif); + +/* This is analogous to the raw API, except it uses Java parameter + packing, even on 64-bit machines. I.e. on 64-bit machines + longs and doubles are followed by an empty 64-bit word. */ +void +ffi_java_raw_call( +/*@dependent@*/ ffi_cif* cif, + void (*fn)(void), +/*@out@*/ void* rvalue, +/*@dependent@*/ ffi_raw* avalue); + +void +ffi_java_ptrarray_to_raw( + ffi_cif* cif, + void** args, + ffi_raw* raw); + +void +ffi_java_raw_to_ptrarray( + ffi_cif* cif, + ffi_raw* raw, + void** args); + +size_t +ffi_java_raw_size( + ffi_cif* cif); + +/* ---- Definitions for closures ----------------------------------------- */ + +#if FFI_CLOSURES + +typedef struct ffi_closure { + char tramp[FFI_TRAMPOLINE_SIZE]; + ffi_cif* cif; + void (*fun)(ffi_cif*,void*,void**,void*); + void* user_data; +} ffi_closure; + +ffi_status +ffi_prep_closure( + ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void* user_data); + +typedef struct ffi_raw_closure { + char tramp[FFI_TRAMPOLINE_SIZE]; + ffi_cif* cif; + +#if !FFI_NATIVE_RAW_API + /* if this is enabled, then a raw closure has the same layout + as a regular closure. We use this to install an intermediate + handler to do the transaltion, void** -> ffi_raw*. */ + void (*translate_args)(ffi_cif*,void*,void**,void*); + void* this_closure; +#endif + + void (*fun)(ffi_cif*,void*,ffi_raw*,void*); + void* user_data; +} ffi_raw_closure; + +ffi_status +ffi_prep_raw_closure( + ffi_raw_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void* user_data); + +ffi_status +ffi_prep_java_raw_closure( + ffi_raw_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void* user_data); + +#endif // FFI_CLOSURES + +/* ---- Public interface definition -------------------------------------- */ + +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); + +void +ffi_call( +/*@dependent@*/ ffi_cif* cif, + void (*fn)(void), +/*@out@*/ void* rvalue, +/*@dependent@*/ void** avalue); + +/* Useful for eliminating compiler warnings */ +#define FFI_FN(f) ((void (*)(void))f) + +#endif // #ifndef LIBFFI_ASM +/* ---- Definitions shared with assembly code ---------------------------- */ + +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 + +#ifdef HAVE_LONG_DOUBLE +# define FFI_TYPE_LONGDOUBLE 4 +#else +# define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif + +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 + +/* This should always refer to the last type code (for sanity checks) */ +#define FFI_TYPE_LAST FFI_TYPE_POINTER + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef LIBFFI_H
\ No newline at end of file diff --git a/Modules/_ctypes/libffi_osx/include/ffi_common.h b/Modules/_ctypes/libffi_osx/include/ffi_common.h new file mode 100644 index 0000000..685a358 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/include/ffi_common.h @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------- + ffi_common.h - Copyright (c) 1996 Red Hat, Inc. + + Common internal definitions and macros. Only necessary for building + libffi. + ----------------------------------------------------------------------- */ + +#ifndef FFI_COMMON_H +#define FFI_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "fficonfig.h" + +/* Do not move this. Some versions of AIX are very picky about where + this is positioned. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX +# pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char* alloca(); +# endif +# endif +# endif +#endif + +/* Check for the existence of memcpy. */ +#if STDC_HEADERS +# include <string.h> +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy((s), (d), (n)) +# endif +#endif + +/*#if defined(FFI_DEBUG) +#include <stdio.h> +#endif*/ + +#ifdef FFI_DEBUG +#include <stdio.h> + +/*@exits@*/ void +ffi_assert( +/*@temp@*/ char* expr, +/*@temp@*/ char* file, + int line); +void +ffi_stop_here(void); +void +ffi_type_test( +/*@temp@*/ /*@out@*/ ffi_type* a, +/*@temp@*/ char* file, + int line); + +# define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) +# define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) +# define FFI_ASSERT_VALID_TYPE(x) ffi_type_test(x, __FILE__, __LINE__) +#else +# define FFI_ASSERT(x) +# define FFI_ASSERT_AT(x, f, l) +# define FFI_ASSERT_VALID_TYPE(x) +#endif // #ifdef FFI_DEBUG + +#define ALIGN(v, a) (((size_t)(v) + (a) - 1) & ~((a) - 1)) + +/* Perform machine dependent cif processing */ +ffi_status +ffi_prep_cif_machdep( + ffi_cif* cif); + +/* Extended cif, used in callback from assembly routine */ +typedef struct extended_cif { +/*@dependent@*/ ffi_cif* cif; +/*@dependent@*/ void* rvalue; +/*@dependent@*/ void** avalue; +} extended_cif; + +/* Terse sized type definitions. */ +typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); +typedef signed int SINT8 __attribute__((__mode__(__QI__))); +typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); +typedef signed int SINT16 __attribute__((__mode__(__HI__))); +typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); +typedef signed int SINT32 __attribute__((__mode__(__SI__))); +typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); +typedef signed int SINT64 __attribute__((__mode__(__DI__))); +typedef float FLOAT32; + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef FFI_COMMON_H
\ No newline at end of file diff --git a/Modules/_ctypes/libffi_osx/include/fficonfig.h b/Modules/_ctypes/libffi_osx/include/fficonfig.h new file mode 100644 index 0000000..2172490 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/include/fficonfig.h @@ -0,0 +1,150 @@ +/* Manually created fficonfig.h for Darwin on PowerPC or Intel + + This file is manually generated to do away with the need for autoconf and + therefore make it easier to cross-compile and build fat binaries. + + NOTE: This file was added by PyObjC. +*/ + +#ifndef MACOSX +#error "This file is only supported on Mac OS X" +#endif + +#if defined(__i386__) +# define BYTEORDER 1234 +# undef HOST_WORDS_BIG_ENDIAN +# undef WORDS_BIGENDIAN +# define SIZEOF_DOUBLE 8 +# define HAVE_LONG_DOUBLE 1 +# define SIZEOF_LONG_DOUBLE 16 + +#elif defined(__x86_64__) +# define BYTEORDER 1234 +# undef HOST_WORDS_BIG_ENDIAN +# undef WORDS_BIGENDIAN +# define SIZEOF_DOUBLE 8 +# define HAVE_LONG_DOUBLE 1 +# define SIZEOF_LONG_DOUBLE 16 + +#elif defined(__ppc__) +# define BYTEORDER 4321 +# define HOST_WORDS_BIG_ENDIAN 1 +# define WORDS_BIGENDIAN 1 +# define SIZEOF_DOUBLE 8 +# if __GNUC__ >= 4 +# define HAVE_LONG_DOUBLE 1 +# define SIZEOF_LONG_DOUBLE 16 +# else +# undef HAVE_LONG_DOUBLE +# define SIZEOF_LONG_DOUBLE 8 +# endif + +#elif defined(__ppc64__) +# define BYTEORDER 4321 +# define HOST_WORDS_BIG_ENDIAN 1 +# define WORDS_BIGENDIAN 1 +# define SIZEOF_DOUBLE 8 +# define HAVE_LONG_DOUBLE 1 +# define SIZEOF_LONG_DOUBLE 16 + +#else +#error "Unknown CPU type" +#endif + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to the flags needed for the .section .eh_frame directive. */ +#define EH_FRAME_FLAGS "aw" + +/* Define this if you want extra debugging. */ +/* #undef FFI_DEBUG */ + +/* Define this is you do not want support for the raw API. */ +#define FFI_NO_RAW_API 1 + +/* Define this if you do not want support for aggregate types. */ +/* #undef FFI_NO_STRUCTS */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */ +#define HAVE_ALLOCA_H 1 + +/* Define if your assembler supports .register. */ +/* #undef HAVE_AS_REGISTER_PSEUDO_OP */ + +/* Define if your assembler and linker support unaligned PC relative relocs. */ +/* #undef HAVE_AS_SPARC_UA_PCREL */ + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +#define HAVE_MMAP_ANON 1 + +/* Define if mmap of /dev/zero works. */ +/* #undef HAVE_MMAP_DEV_ZERO */ + +/* Define if read-only mmap of a plain file works. */ +#define HAVE_MMAP_FILE 1 + +/* Define if .eh_frame sections should be read-only. */ +/* #undef HAVE_RO_EH_FRAME */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "libffi" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "http://gcc.gnu.org/bugs.html" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libffi" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libffi 2.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libffi" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.1" + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define this if you are using Purify and want to suppress spurious messages. */ +/* #undef USING_PURIFY */ + +/* Version number of package */ +#define VERSION "2.1-pyobjc" + +#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE +# ifdef LIBFFI_ASM +# define FFI_HIDDEN(name) .hidden name +# else +# define FFI_HIDDEN __attribute__((visibility ("hidden"))) +# endif +#else +# ifdef LIBFFI_ASM +# define FFI_HIDDEN(name) +# else +# define FFI_HIDDEN +# endif +#endif
\ No newline at end of file diff --git a/Modules/_ctypes/libffi_osx/include/ffitarget.h b/Modules/_ctypes/libffi_osx/include/ffitarget.h new file mode 100644 index 0000000..faaa30d --- /dev/null +++ b/Modules/_ctypes/libffi_osx/include/ffitarget.h @@ -0,0 +1,13 @@ +/* Dispatch to the right ffitarget file. This file is PyObjC specific; in a + normal build, the build environment copies the file to the right location or + sets up the right include flags. We want to do neither because that would + make building fat binaries harder. +*/ + +#if defined(__i386__) || defined(__x86_64__) +#include "x86-ffitarget.h" +#elif defined(__ppc__) || defined(__ppc64__) +#include "ppc-ffitarget.h" +#else +#error "Unsupported CPU type" +#endif
\ No newline at end of file diff --git a/Modules/_ctypes/libffi_osx/include/ppc-ffitarget.h b/Modules/_ctypes/libffi_osx/include/ppc-ffitarget.h new file mode 100644 index 0000000..2318421 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/include/ppc-ffitarget.h @@ -0,0 +1,104 @@ +/* -----------------------------------------------------------------*-C-*- + ppc-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__)) || \ + (defined(POWERPC_DARWIN) && defined(__ppc64__)) +#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 + +#ifdef POWERPC_FREEBSD + FFI_SYSV, + FFI_GCC_SYSV, + FFI_LINUX64, + FFI_DEFAULT_ABI = FFI_SYSV, +#endif + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; + +#endif // #ifndef LIBFFI_ASM + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +/* Needed for FFI_SYSV small structure returns. */ +#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST) + +#if defined(POWERPC64) /*|| defined(POWERPC_AIX)*/ +# define FFI_TRAMPOLINE_SIZE 48 +#elif defined(POWERPC_AIX) +# define FFI_TRAMPOLINE_SIZE 24 +#else +# define FFI_TRAMPOLINE_SIZE 40 +#endif + +#ifndef LIBFFI_ASM +# if defined(POWERPC_DARWIN) || defined(POWERPC_AIX) +typedef struct ffi_aix_trampoline_struct { + void* code_pointer; /* Pointer to ffi_closure_ASM */ + void* toc; /* TOC */ + void* static_chain; /* Pointer to closure */ +} ffi_aix_trampoline_struct; +# endif +#endif // #ifndef LIBFFI_ASM + +#endif // #ifndef LIBFFI_TARGET_H
\ No newline at end of file diff --git a/Modules/_ctypes/libffi_osx/include/x86-ffitarget.h b/Modules/_ctypes/libffi_osx/include/x86-ffitarget.h new file mode 100644 index 0000000..55c2b6c --- /dev/null +++ b/Modules/_ctypes/libffi_osx/include/x86-ffitarget.h @@ -0,0 +1,88 @@ +/* -----------------------------------------------------------------*-C-*- + x86-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 + +#if defined(__x86_64__) +# ifndef X86_64 +# define X86_64 +# endif +#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 // #ifndef LIBFFI_ASM + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 + +#if defined(X86_64) || (defined(__x86_64__) && defined(X86_DARWIN)) +# define FFI_TRAMPOLINE_SIZE 24 +# define FFI_NATIVE_RAW_API 0 +#else +# define FFI_TRAMPOLINE_SIZE 10 +# define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ +#endif + +#endif // #ifndef LIBFFI_TARGET_H
\ No newline at end of file diff --git a/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin.S b/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin.S new file mode 100644 index 0000000..0a95771 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin.S @@ -0,0 +1,369 @@ +#if defined(__ppc__) || defined(__ppc64__) + +/* ----------------------------------------------------------------------- + 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> +#include <ppc-darwin.h> +#include <architecture/ppc/mode_independent_asm.h> + +.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: +#if defined(__ppc64__) + /* Allocate the stack space we need. + r4 (size of input data) + 48 bytes (linkage area) + 40 bytes (saved registers) + 8 bytes (extra FPR) + r4 + 96 bytes total + */ + + addi r4,r4,-96 // Add our overhead. + li r0,-32 // Align to 32 bytes. + and r4,r4,r0 +#endif + stgux r1,r1,r4 // Grow the stack. + mflr r9 + + /* Save registers we use. */ +#if defined(__ppc64__) + std r27,-40(r8) +#endif + stg r28,MODE_CHOICE(-16,-32)(r8) + stg r29,MODE_CHOICE(-12,-24)(r8) + stg r30,MODE_CHOICE(-8,-16)(r8) + stg r31,MODE_CHOICE(-4,-8)(r8) + stg r9,SF_RETURN(r8) /* return address */ +#if !defined(POWERPC_DARWIN) /* TOC unused in OS X */ + stg r2,MODE_CHOICE(20,40)(r1) +#endif + +LCFI1: +#if defined(__ppc64__) + mr r27,r3 // our extended_cif +#endif + /* 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 +#if !defined(POWERPC_DARWIN) /* TOC unused in OS X */ + lg r2,MODE_CHOICE(20,40)(r1) +#endif + + /* Now do the call. + Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40,r31 + + /* Load all those argument registers. + We have set up a nice stack frame, just load it into registers. */ + lg r3,SF_ARG1(r1) + lg r4,SF_ARG2(r1) + lg r5,SF_ARG3(r1) + lg r6,SF_ARG4(r1) + nop + lg r7,SF_ARG5(r1) + lg r8,SF_ARG6(r1) + lg r9,SF_ARG7(r1) + lg r10,SF_ARG8(r1) + + /* Load all the FP registers. */ + bf 6,L2 /* No floats to load. */ +#if defined(__ppc64__) + lfd f1,MODE_CHOICE(-16,-40)-(14*8)(r28) + lfd f2,MODE_CHOICE(-16,-40)-(13*8)(r28) + lfd f3,MODE_CHOICE(-16,-40)-(12*8)(r28) + lfd f4,MODE_CHOICE(-16,-40)-(11*8)(r28) + nop + lfd f5,MODE_CHOICE(-16,-40)-(10*8)(r28) + lfd f6,MODE_CHOICE(-16,-40)-(9*8)(r28) + lfd f7,MODE_CHOICE(-16,-40)-(8*8)(r28) + lfd f8,MODE_CHOICE(-16,-40)-(7*8)(r28) + nop + lfd f9,MODE_CHOICE(-16,-40)-(6*8)(r28) + lfd f10,MODE_CHOICE(-16,-40)-(5*8)(r28) + lfd f11,MODE_CHOICE(-16,-40)-(4*8)(r28) + lfd f12,MODE_CHOICE(-16,-40)-(3*8)(r28) + nop + lfd f13,MODE_CHOICE(-16,-40)-(2*8)(r28) + lfd f14,MODE_CHOICE(-16,-40)-(1*8)(r28) +#elif defined(__ppc__) + lfd f1,MODE_CHOICE(-16,-40)-(13*8)(r28) + lfd f2,MODE_CHOICE(-16,-40)-(12*8)(r28) + lfd f3,MODE_CHOICE(-16,-40)-(11*8)(r28) + lfd f4,MODE_CHOICE(-16,-40)-(10*8)(r28) + nop + lfd f5,MODE_CHOICE(-16,-40)-(9*8)(r28) + lfd f6,MODE_CHOICE(-16,-40)-(8*8)(r28) + lfd f7,MODE_CHOICE(-16,-40)-(7*8)(r28) + lfd f8,MODE_CHOICE(-16,-40)-(6*8)(r28) + nop + lfd f9,MODE_CHOICE(-16,-40)-(5*8)(r28) + lfd f10,MODE_CHOICE(-16,-40)-(4*8)(r28) + lfd f11,MODE_CHOICE(-16,-40)-(3*8)(r28) + lfd f12,MODE_CHOICE(-16,-40)-(2*8)(r28) + nop + lfd f13,MODE_CHOICE(-16,-40)-(1*8)(r28) +#else +#error undefined architecture +#endif + +L2: + mr r12,r29 // Put the target address in r12 as specified. + mtctr r12 // Get the address to call into CTR. + nop + nop + bctrl // Make the call. + + // Deal with the return value. +#if defined(__ppc64__) + mtcrf 0x3,r31 // flags in cr6 and cr7 + bt 27,L(st_return_value) +#elif defined(__ppc__) + mtcrf 0x1,r31 // flags in cr7 +#else +#error undefined architecture +#endif + + bt 30,L(done_return_value) + bt 29,L(fp_return_value) + stg r3,0(r30) +#if defined(__ppc__) + bf 28,L(done_return_value) // Store the second long if necessary. + stg r4,4(r30) +#endif + // Fall through + +L(done_return_value): + lg r1,0(r1) // Restore stack pointer. + // Restore the registers we used. + lg r9,SF_RETURN(r1) // return address + lg r31,MODE_CHOICE(-4,-8)(r1) + mtlr r9 + lg r30,MODE_CHOICE(-8,-16)(r1) + lg r29,MODE_CHOICE(-12,-24)(r1) + lg r28,MODE_CHOICE(-16,-32)(r1) +#if defined(__ppc64__) + ld r27,-40(r1) +#endif + blr + +#if defined(__ppc64__) +L(st_return_value): + // Grow the stack enough to fit the registers. Leave room for 8 args + // to trample the 1st 8 slots in param area. + stgu r1,-SF_ROUND(280)(r1) // 64 + 104 + 48 + 64 + + // Store GPRs + std r3,SF_ARG9(r1) + std r4,SF_ARG10(r1) + std r5,SF_ARG11(r1) + std r6,SF_ARG12(r1) + nop + std r7,SF_ARG13(r1) + std r8,SF_ARG14(r1) + std r9,SF_ARG15(r1) + std r10,SF_ARG16(r1) + + // Store FPRs + nop + bf 26,L(call_struct_to_ram_form) + stfd f1,SF_ARG17(r1) + stfd f2,SF_ARG18(r1) + stfd f3,SF_ARG19(r1) + stfd f4,SF_ARG20(r1) + nop + stfd f5,SF_ARG21(r1) + stfd f6,SF_ARG22(r1) + stfd f7,SF_ARG23(r1) + stfd f8,SF_ARG24(r1) + nop + stfd f9,SF_ARG25(r1) + stfd f10,SF_ARG26(r1) + stfd f11,SF_ARG27(r1) + stfd f12,SF_ARG28(r1) + nop + stfd f13,SF_ARG29(r1) + +L(call_struct_to_ram_form): + ld r3,0(r27) // extended_cif->cif* + ld r3,16(r3) // ffi_cif->rtype* + addi r4,r1,SF_ARG9 // stored GPRs + addi r6,r1,SF_ARG17 // stored FPRs + li r5,0 // GPR size ptr (NULL) + li r7,0 // FPR size ptr (NULL) + li r8,0 // FPR count ptr (NULL) + li r10,0 // struct offset (NULL) + mr r9,r30 // return area + bl Lffi64_struct_to_ram_form$stub + lg r1,0(r1) // Restore stack pointer. + b L(done_return_value) +#endif + +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) */ + +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 ; Length of Common Information Entry +LSCIE1: + .long 0x0 ; CIE Identifier Tag + .byte 0x1 ; CIE Version + .ascii "zR\0" ; CIE Augmentation + .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor + .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x90 ; FDE Encoding (indirect pcrel) + .byte 0xc ; DW_CFA_def_cfa + .byte 0x1 ; uleb128 0x1 + .byte 0x0 ; uleb128 0x0 + .align LOG2_GPR_BYTES +LECIE1: +.globl _ffi_call_DARWIN.eh +_ffi_call_DARWIN.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 ; FDE Length + +LASFDE1: + .long LASFDE1-EH_frame1 ; FDE CIE offset + .g_long LLFB0$non_lazy_ptr-. ; FDE initial location + .set L$set$3,LFE1-LFB0 + .g_long L$set$3 ; FDE address range + .byte 0x0 ; uleb128 0x0; Augmentation size + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-LFB1 + .long L$set$4 + .byte 0xd ; DW_CFA_def_cfa_register + .byte 0x08 ; uleb128 0x08 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$5,LCFI1-LCFI0 + .long L$set$5 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .byte 0x9f ; DW_CFA_offset, column 0x1f + .byte 0x1 ; uleb128 0x1 + .byte 0x9e ; DW_CFA_offset, column 0x1e + .byte 0x2 ; uleb128 0x2 + .byte 0x9d ; DW_CFA_offset, column 0x1d + .byte 0x3 ; uleb128 0x3 + .byte 0x9c ; DW_CFA_offset, column 0x1c + .byte 0x4 ; uleb128 0x4 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$6,LCFI2-LCFI1 + .long L$set$6 + .byte 0xd ; DW_CFA_def_cfa_register + .byte 0x1c ; uleb128 0x1c + .align LOG2_GPR_BYTES +LEFDE1: +.data + .align LOG2_GPR_BYTES +LLFB0$non_lazy_ptr: + .g_long LFB0 + +#if defined(__ppc64__) +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align LOG2_GPR_BYTES + +Lffi64_struct_to_ram_form$stub: + .indirect_symbol _ffi64_struct_to_ram_form + mflr r0 + bcl 20,31,LO$ffi64_struct_to_ram_form + +LO$ffi64_struct_to_ram_form: + mflr r11 + addis r11,r11,ha16(L_ffi64_struct_to_ram_form$lazy_ptr - LO$ffi64_struct_to_ram_form) + mtlr r0 + lgu r12,lo16(L_ffi64_struct_to_ram_form$lazy_ptr - LO$ffi64_struct_to_ram_form)(r11) + mtctr r12 + bctr + +.lazy_symbol_pointer +L_ffi64_struct_to_ram_form$lazy_ptr: + .indirect_symbol _ffi64_struct_to_ram_form + .g_long dyld_stub_binding_helper + +#endif // __ppc64__ +#endif // __ppc__ || __ppc64__ diff --git a/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin.h b/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin.h new file mode 100644 index 0000000..00e7e4d --- /dev/null +++ b/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin.h @@ -0,0 +1,106 @@ +/* ----------------------------------------------------------------------- + ppc-darwin.h - Copyright (c) 2002, 2003, 2004, 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. + ----------------------------------------------------------------------- */ + + +#define L(x) x + +#define SF_ARG9 MODE_CHOICE(56,112) +#define SF_ARG10 MODE_CHOICE(60,120) +#define SF_ARG11 MODE_CHOICE(64,128) +#define SF_ARG12 MODE_CHOICE(68,136) +#define SF_ARG13 MODE_CHOICE(72,144) +#define SF_ARG14 MODE_CHOICE(76,152) +#define SF_ARG15 MODE_CHOICE(80,160) +#define SF_ARG16 MODE_CHOICE(84,168) +#define SF_ARG17 MODE_CHOICE(88,176) +#define SF_ARG18 MODE_CHOICE(92,184) +#define SF_ARG19 MODE_CHOICE(96,192) +#define SF_ARG20 MODE_CHOICE(100,200) +#define SF_ARG21 MODE_CHOICE(104,208) +#define SF_ARG22 MODE_CHOICE(108,216) +#define SF_ARG23 MODE_CHOICE(112,224) +#define SF_ARG24 MODE_CHOICE(116,232) +#define SF_ARG25 MODE_CHOICE(120,240) +#define SF_ARG26 MODE_CHOICE(124,248) +#define SF_ARG27 MODE_CHOICE(128,256) +#define SF_ARG28 MODE_CHOICE(132,264) +#define SF_ARG29 MODE_CHOICE(136,272) + +#define ASM_NEEDS_REGISTERS 4 +#define NUM_GPR_ARG_REGISTERS 8 +#define NUM_FPR_ARG_REGISTERS 13 + +#define FFI_TYPE_1_BYTE(x) ((x) == FFI_TYPE_UINT8 || (x) == FFI_TYPE_SINT8) +#define FFI_TYPE_2_BYTE(x) ((x) == FFI_TYPE_UINT16 || (x) == FFI_TYPE_SINT16) +#define FFI_TYPE_4_BYTE(x) \ + ((x) == FFI_TYPE_UINT32 || (x) == FFI_TYPE_SINT32 ||\ + (x) == FFI_TYPE_INT || (x) == FFI_TYPE_FLOAT) + + +#if !defined(LIBFFI_ASM) + +enum { + FLAG_RETURNS_NOTHING = 1 << (31 - 30), // cr7 + FLAG_RETURNS_FP = 1 << (31 - 29), + FLAG_RETURNS_64BITS = 1 << (31 - 28), + FLAG_RETURNS_128BITS = 1 << (31 - 31), + + FLAG_RETURNS_STRUCT = 1 << (31 - 27), // cr6 + FLAG_STRUCT_CONTAINS_FP = 1 << (31 - 26), + + 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) +}; + + +void ffi_prep_args(extended_cif* inEcif, unsigned *const stack); + +typedef union +{ + float f; + double d; +} ffi_dblfl; + +int ffi_closure_helper_DARWIN( ffi_closure* closure, + void* rvalue, unsigned long* pgr, + ffi_dblfl* pfr); + + +#if defined(__ppc64__) +void ffi64_struct_to_ram_form(const ffi_type*, const char*, unsigned int*, + const char*, unsigned int*, unsigned int*, char*, unsigned int*); +void ffi64_struct_to_reg_form(const ffi_type*, const char*, unsigned int*, + unsigned int*, char*, unsigned int*, char*, unsigned int*); +bool ffi64_stret_needs_ptr(const ffi_type* inType, + unsigned short*, unsigned short*); +bool ffi64_struct_contains_fp(const ffi_type* inType); +unsigned int ffi64_data_size(const ffi_type* inType); + + + +#endif + +#endif // !defined(LIBFFI_ASM) diff --git a/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin_closure.S b/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin_closure.S new file mode 100644 index 0000000..227dd1a --- /dev/null +++ b/Modules/_ctypes/libffi_osx/powerpc/ppc-darwin_closure.S @@ -0,0 +1,325 @@ +#if defined(__ppc__) + +/* ----------------------------------------------------------------------- + darwin_closure.S - Copyright (c) 2002, 2003, 2004, Free Software Foundation, + Inc. based on ppc_closure.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM + +#include <ffi.h> +#include <ppc-ffitarget.h> // for FFI_TRAMPOLINE_SIZE +#include <ppc-darwin.h> +#include <architecture/ppc/mode_independent_asm.h> + + .file "ppc-darwin_closure.S" +.text + .align LOG2_GPR_BYTES + .globl _ffi_closure_ASM + +.text + .align LOG2_GPR_BYTES + +_ffi_closure_ASM: +LFB1: + mflr r0 /* extract return address */ + stg r0,MODE_CHOICE(8,16)(r1) /* save return address */ + +LCFI0: + /* 24/48 bytes (Linkage Area) + 32/64 bytes (outgoing parameter area, always reserved) + 104 bytes (13*8 from FPR) + 16/32 bytes (result) + 176/232 total bytes */ + + /* skip over caller save area and keep stack aligned to 16/32. */ + stgu r1,-SF_ROUND(MODE_CHOICE(176,248))(r1) + +LCFI1: + /* We want to build up an area for the parameters passed + in registers. (both floating point and integer) */ + + /* 176/256 bytes (callee stack frame aligned to 16/32) + 24/48 bytes (caller linkage area) + 200/304 (start of caller parameter area aligned to 4/8) + */ + + /* Save GPRs 3 - 10 (aligned to 4/8) + in the parents outgoing area. */ + stg r3,MODE_CHOICE(200,304)(r1) + stg r4,MODE_CHOICE(204,312)(r1) + stg r5,MODE_CHOICE(208,320)(r1) + stg r6,MODE_CHOICE(212,328)(r1) + stg r7,MODE_CHOICE(216,336)(r1) + stg r8,MODE_CHOICE(220,344)(r1) + stg r9,MODE_CHOICE(224,352)(r1) + stg r10,MODE_CHOICE(228,360)(r1) + + /* Save FPRs 1 - 13. (aligned to 8) */ + stfd f1,MODE_CHOICE(56,112)(r1) + stfd f2,MODE_CHOICE(64,120)(r1) + stfd f3,MODE_CHOICE(72,128)(r1) + stfd f4,MODE_CHOICE(80,136)(r1) + stfd f5,MODE_CHOICE(88,144)(r1) + stfd f6,MODE_CHOICE(96,152)(r1) + stfd f7,MODE_CHOICE(104,160)(r1) + stfd f8,MODE_CHOICE(112,168)(r1) + stfd f9,MODE_CHOICE(120,176)(r1) + stfd f10,MODE_CHOICE(128,184)(r1) + stfd f11,MODE_CHOICE(136,192)(r1) + stfd f12,MODE_CHOICE(144,200)(r1) + stfd f13,MODE_CHOICE(152,208)(r1) + + /* Set up registers for the routine that actually does the work. + Get the context pointer from the trampoline. */ + mr r3,r11 + + /* Load the pointer to the result storage. */ + /* current stack frame size - ((4/8 * 4) + saved registers) */ + addi r4,r1,MODE_CHOICE(160,216) + + /* Load the pointer to the saved gpr registers. */ + addi r5,r1,MODE_CHOICE(200,304) + + /* Load the pointer to the saved fpr registers. */ + addi r6,r1,MODE_CHOICE(56,112) + + /* Make the call. */ + bl Lffi_closure_helper_DARWIN$stub + + /* Now r3 contains the return type + so use it to look up in a table + so we know how to deal with each type. */ + + /* Look the proper starting point in table + by using return type as offset. */ + addi r5,r1,MODE_CHOICE(160,216) // 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 + +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,MODE_CHOICE(0,4)(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_FLOAT */ +Lret_type2: + lfs f1,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_DOUBLE */ +Lret_type3: + lfd f1,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_LONGDOUBLE */ +Lret_type4: + lfd f1,0(r5) + lfd f2,8(r5) + b Lfinish + nop + +/* case FFI_TYPE_UINT8 */ +Lret_type5: + lbz r3,MODE_CHOICE(3,7)(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT8 */ +Lret_type6: + lbz r3,MODE_CHOICE(3,7)(r5) + extsb r3,r3 + b Lfinish + nop + +/* case FFI_TYPE_UINT16 */ +Lret_type7: + lhz r3,MODE_CHOICE(2,6)(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT16 */ +Lret_type8: + lha r3,MODE_CHOICE(2,6)(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_UINT32 */ +Lret_type9: // same as Lret_type1 + lwz r3,MODE_CHOICE(0,4)(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT32 */ +Lret_type10: // same as Lret_type1 + lwz r3,MODE_CHOICE(0,4)(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: // same as Lret_type11 + lwz r3,0(r5) + lwz r4,4(r5) + b Lfinish + nop + +/* case FFI_TYPE_STRUCT */ +Lret_type13: + b MODE_CHOICE(Lfinish,Lret_struct) + nop + nop + nop + +/* End 16-byte aligned cases */ +/* case FFI_TYPE_POINTER */ +// This case assumes that FFI_TYPE_POINTER == FFI_TYPE_LAST. If more types +// are added in future, the following code will need to be updated and +// padded to 16 bytes. +Lret_type14: + lg r3,0(r5) + +/* case done */ +Lfinish: + addi r1,r1,SF_ROUND(MODE_CHOICE(176,248)) // Restore stack pointer. + lg r0,MODE_CHOICE(8,16)(r1) /* Get return address. */ + mtlr r0 /* Reset link register. */ + blr + +/* END(ffi_closure_ASM) */ + +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 ; Length of Common Information Entry +LSCIE1: + .long 0x0 ; CIE Identifier Tag + .byte 0x1 ; CIE Version + .ascii "zR\0" ; CIE Augmentation + .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor + .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x90 ; FDE Encoding (indirect pcrel) + .byte 0xc ; DW_CFA_def_cfa + .byte 0x1 ; uleb128 0x1 + .byte 0x0 ; uleb128 0x0 + .align LOG2_GPR_BYTES +LECIE1: +.globl _ffi_closure_ASM.eh +_ffi_closure_ASM.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 ; FDE Length + +LASFDE1: + .long LASFDE1-EH_frame1 ; FDE CIE offset + .g_long LLFB1$non_lazy_ptr-. ; FDE initial location + .set L$set$3,LFE1-LFB1 + .g_long L$set$3 ; FDE address range + .byte 0x0 ; uleb128 0x0; Augmentation size + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$3,LCFI1-LCFI0 + .long L$set$3 + .byte 0xe ; DW_CFA_def_cfa_offset + .byte 176,1 ; uleb128 176 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-LFB1 + .long L$set$4 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .align LOG2_GPR_BYTES + +LEFDE1: +.data + .align LOG2_GPR_BYTES +LDFCM0: +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align LOG2_GPR_BYTES + +Lffi_closure_helper_DARWIN$stub: + .indirect_symbol _ffi_closure_helper_DARWIN + mflr r0 + bcl 20,31,LO$ffi_closure_helper_DARWIN + +LO$ffi_closure_helper_DARWIN: + mflr r11 + addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN) + mtlr r0 + lgu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)(r11) + mtctr r12 + bctr + +.lazy_symbol_pointer +L_ffi_closure_helper_DARWIN$lazy_ptr: + .indirect_symbol _ffi_closure_helper_DARWIN + .g_long dyld_stub_binding_helper + +.data + .align LOG2_GPR_BYTES +LLFB1$non_lazy_ptr: + .g_long LFB1 + +#endif // __ppc__ diff --git a/Modules/_ctypes/libffi_osx/powerpc/ppc-ffi_darwin.c b/Modules/_ctypes/libffi_osx/powerpc/ppc-ffi_darwin.c new file mode 100644 index 0000000..3c682ca --- /dev/null +++ b/Modules/_ctypes/libffi_osx/powerpc/ppc-ffi_darwin.c @@ -0,0 +1,1775 @@ +#if defined(__ppc__) || defined(__ppc64__) + +/* ----------------------------------------------------------------------- + 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 <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include "ppc-darwin.h" +#include <architecture/ppc/mode_independent_asm.h> + +#if 0 +#if defined(POWERPC_DARWIN) +#include <libkern/OSCacheControl.h> // for sys_icache_invalidate() +#endif + +#else + +/* Explicit prototype instead of including a header to allow compilation + * on Tiger systems. + */ + +#pragma weak sys_icache_invalidate +extern void sys_icache_invalidate(void *start, size_t len); + +#endif + +extern void ffi_closure_ASM(void); + +// 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; + +/* 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/8 | stack pointer here + |--------------------------------------------|-\ <<< on entry to + | Saved r28-r31 (4/8)*4 | | ffi_call_DARWIN + |--------------------------------------------| | + | Parameters (at least 8*(4/8)=32/64) | | (176) +112 - +288 + |--------------------------------------------| | + | Space for GPR2 4/8 | | + |--------------------------------------------| | stack | + | Reserved (4/8)*2 | | grows | + |--------------------------------------------| | down V + | Space for callee's LR 4/8 | | + |--------------------------------------------| | lower addresses + | Saved CR 4/8 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4/8 | | during + |--------------------------------------------|-/ <<< ffi_call_DARWIN + + Note: ppc64 CR is saved in the low word of a long on the stack. +*/ + +/*@-exportheader@*/ +void +ffi_prep_args( + extended_cif* inEcif, + unsigned *const stack) +/*@=exportheader@*/ +{ + /* Copy the ecif to a local var so we can trample the arg. + BC note: test this with GP later for possible problems... */ + volatile extended_cif* ecif = inEcif; + + const unsigned bytes = ecif->cif->bytes; + const unsigned flags = ecif->cif->flags; + + /* Cast the stack arg from int* to long*. sizeof(long) == 4 in 32-bit mode + and 8 in 64-bit mode. */ + unsigned long *const longStack = (unsigned long *const)stack; + + /* 'stacktop' points at the previous backchain pointer. */ +#if defined(__ppc64__) + // In ppc-darwin.s, an extra 96 bytes is reserved for the linkage area, + // saved registers, and an extra FPR. + unsigned long *const stacktop = + (unsigned long *)(unsigned long)((char*)longStack + bytes + 96); +#elif defined(__ppc__) + unsigned long *const stacktop = longStack + (bytes / sizeof(long)); +#else +#error undefined architecture +#endif + + /* '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; + +#if defined(__ppc64__) + // 64-bit saves an extra register, and uses an extra FPR. Knock fpr_base + // down a couple pegs. + fpr_base -= 2; +#endif + + unsigned int fparg_count = 0; + + /* 'next_arg' grows up as we put parameters in it. */ + unsigned long* next_arg = longStack + 6; /* 6 reserved positions. */ + + int i; + double double_tmp; + void** p_argv = ecif->avalue; + unsigned long gprvalue; + ffi_type** ptr = ecif->cif->arg_types; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT(stack == SF_ROUND(stack)); + FFI_ASSERT(stacktop == SF_ROUND(stacktop)); + FFI_ASSERT(bytes == SF_ROUND(bytes)); + + /* 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 long)(char*)ecif->rvalue; + + /* Now for the arguments. */ + for (i = ecif->cif->nargs; 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 shadowed for the + benefit of vararg and pre-ANSI functions. */ + case FFI_TYPE_FLOAT: + double_tmp = *(float*)*p_argv; + + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = double_tmp; + + *(double*)next_arg = 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) + *fpr_base++ = double_tmp; + + *(double*)next_arg = double_tmp; + + next_arg += MODE_CHOICE(2,1); + fparg_count++; + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#if defined(__ppc64__) + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *(long double*)fpr_base = *(long double*)*p_argv; +#elif defined(__ppc__) + if (fparg_count < NUM_FPR_ARG_REGISTERS - 1) + *(long double*)fpr_base = *(long double*)*p_argv; + else if (fparg_count == NUM_FPR_ARG_REGISTERS - 1) + *(double*)fpr_base = *(double*)*p_argv; +#else +#error undefined architecture +#endif + + *(long double*)next_arg = *(long double*)*p_argv; + fparg_count += 2; + fpr_base += 2; + next_arg += MODE_CHOICE(4,2); + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + + break; +#endif // FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#if defined(__ppc64__) + gprvalue = *(long long*)*p_argv; + goto putgpr; +#elif defined(__ppc__) + *(long long*)next_arg = *(long long*)*p_argv; + next_arg += 2; + break; +#else +#error undefined architecture +#endif + + case FFI_TYPE_POINTER: + gprvalue = *(unsigned long*)*p_argv; + goto putgpr; + + case FFI_TYPE_UINT8: + gprvalue = *(unsigned char*)*p_argv; + goto putgpr; + + case FFI_TYPE_SINT8: + gprvalue = *(signed char*)*p_argv; + goto putgpr; + + case FFI_TYPE_UINT16: + gprvalue = *(unsigned short*)*p_argv; + goto putgpr; + + case FFI_TYPE_SINT16: + gprvalue = *(signed short*)*p_argv; + goto putgpr; + + case FFI_TYPE_STRUCT: + { +#if defined(__ppc64__) + unsigned int gprSize = 0; + unsigned int fprSize = 0; + + ffi64_struct_to_reg_form(*ptr, (char*)*p_argv, NULL, &fparg_count, + (char*)next_arg, &gprSize, (char*)fpr_base, &fprSize); + next_arg += gprSize / sizeof(long); + fpr_base += fprSize / sizeof(double); + +#elif defined(__ppc__) + char* 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. */ + unsigned size_al = (*ptr)->size; + + /* If the first member of the struct is a double, then align + the struct to double-word. */ + if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = ALIGN((*ptr)->size, 8); + + if (ecif->cif->abi == FFI_DARWIN) + { + if (size_al < 3) + dest_cpy += 4 - size_al; + } + + memcpy((char*)dest_cpy, (char*)*p_argv, size_al); + next_arg += (size_al + 3) / 4; +#else +#error undefined architecture +#endif + break; + } + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + 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); +} + +#if defined(__ppc64__) + +bool +ffi64_struct_contains_fp( + const ffi_type* inType) +{ + bool containsFP = false; + unsigned int i; + + for (i = 0; inType->elements[i] != NULL && !containsFP; i++) + { + if (inType->elements[i]->type == FFI_TYPE_FLOAT || + inType->elements[i]->type == FFI_TYPE_DOUBLE || + inType->elements[i]->type == FFI_TYPE_LONGDOUBLE) + containsFP = true; + else if (inType->elements[i]->type == FFI_TYPE_STRUCT) + containsFP = ffi64_struct_contains_fp(inType->elements[i]); + } + + return containsFP; +} + +#endif // defined(__ppc64__) + +/* 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; + int intarg_count = 0; + int fparg_count = 0; + unsigned int flags = 0; + unsigned int 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. */ + unsigned int 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 // FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_DOUBLE: + flags |= FLAG_RETURNS_64BITS; + /* Fall through. */ + case FFI_TYPE_FLOAT: + flags |= FLAG_RETURNS_FP; + break; + +#if defined(__ppc64__) + case FFI_TYPE_POINTER: +#endif + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: + { +#if defined(__ppc64__) + + if (ffi64_stret_needs_ptr(cif->rtype, NULL, NULL)) + { + flags |= FLAG_RETVAL_REFERENCE; + flags |= FLAG_RETURNS_NOTHING; + intarg_count++; + } + else + { + flags |= FLAG_RETURNS_STRUCT; + + if (ffi64_struct_contains_fp(cif->rtype)) + flags |= FLAG_STRUCT_CONTAINS_FP; + } + +#elif defined(__ppc__) + + flags |= FLAG_RETVAL_REFERENCE; + flags |= FLAG_RETURNS_NOTHING; + intarg_count++; + +#else +#error undefined architecture +#endif + 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 ( +#if defined(__ppc64__) + fparg_count > NUM_FPR_ARG_REGISTERS + 1 +#elif defined(__ppc__) + fparg_count > NUM_FPR_ARG_REGISTERS +#else +#error undefined architecture +#endif + && intarg_count % 2 != 0) + intarg_count++; + + intarg_count += 2; + break; +#endif // FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + 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 += MODE_CHOICE(2,1); + + 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. */ + if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = ALIGN((*ptr)->size, 8); + +#if defined(__ppc64__) + // Look for FP struct members. + unsigned int j; + + for (j = 0; (*ptr)->elements[j] != NULL; j++) + { + if ((*ptr)->elements[j]->type == FFI_TYPE_FLOAT || + (*ptr)->elements[j]->type == FFI_TYPE_DOUBLE) + { + fparg_count++; + + if (fparg_count > NUM_FPR_ARG_REGISTERS) + intarg_count++; + } + else if ((*ptr)->elements[j]->type == FFI_TYPE_LONGDOUBLE) + { + fparg_count += 2; + + if (fparg_count > NUM_FPR_ARG_REGISTERS + 1) + intarg_count += 2; + } + else + intarg_count++; + } +#elif defined(__ppc__) + intarg_count += (size_al + 3) / 4; +#else +#error undefined architecture +#endif + + break; + + default: + /* Everything else is passed as a 4/8-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + break; + } + } + + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + { + flags |= FLAG_FP_ARGUMENTS; +#if defined(__ppc64__) + bytes += (NUM_FPR_ARG_REGISTERS + 1) * sizeof(double); +#elif defined(__ppc__) + bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); +#else +#error undefined architecture +#endif + } + + /* Stack space. */ +#if defined(__ppc64__) + if ((intarg_count + fparg_count) > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count + fparg_count) * sizeof(long); +#elif defined(__ppc__) + if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count + 2 * fparg_count) * sizeof(long); +#else +#error undefined architecture +#endif + else + bytes += NUM_GPR_ARG_REGISTERS * sizeof(long); + + /* The stack space allocated needs to be a multiple of 16/32 bytes. */ + bytes = SF_ROUND(bytes); + + 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), + void (*fn2)(extended_cif*, unsigned *const)); + +extern void +ffi_call_DARWIN( +/*@out@*/ extended_cif*, + unsigned long, + unsigned, +/*@out@*/ unsigned*, + void (*fn)(void), + void (*fn2)(extended_cif*, unsigned *const)); +/*@=declundef@*/ +/*@=exportheader@*/ + +void +ffi_call( +/*@dependent@*/ ffi_cif* cif, + void (*fn)(void), +/*@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, -(long)cif->bytes, + cif->flags, ecif.rvalue, fn, ffi_prep_args); + /*@=usedef@*/ + break; + + default: + FFI_ASSERT(0); + break; + } +} + +/* 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 +*/ + +#if !defined(POWERPC_DARWIN) + +#define MIN_LINE_SIZE 32 + +static void +flush_icache( + char* addr) +{ +#ifndef _AIX + __asm__ volatile ( + "dcbf 0,%0\n" + "sync\n" + "icbi 0,%0\n" + "sync\n" + "isync" + : : "r" (addr) : "memory"); +#endif +} + +static void +flush_range( + char* addr, + int size) +{ + int i; + + for (i = 0; i < size; i += MIN_LINE_SIZE) + flush_icache(addr + i); + + flush_icache(addr + size - 1); +} + +#endif // !defined(POWERPC_DARWIN) + +ffi_status +ffi_prep_closure( + ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void* user_data) +{ + switch (cif->abi) + { + case FFI_DARWIN: + { + FFI_ASSERT (cif->abi == FFI_DARWIN); + + unsigned int* tramp = (unsigned int*)&closure->tramp[0]; + +#if defined(__ppc64__) + tramp[0] = 0x7c0802a6; // mflr r0 + tramp[1] = 0x429f0005; // bcl 20,31,+0x8 + tramp[2] = 0x7d6802a6; // mflr r11 + tramp[3] = 0x7c0803a6; // mtlr r0 + tramp[4] = 0xe98b0018; // ld r12,24(r11) + tramp[5] = 0x7d8903a6; // mtctr r12 + tramp[6] = 0xe96b0020; // ld r11,32(r11) + tramp[7] = 0x4e800420; // bctr + *(unsigned long*)&tramp[8] = (unsigned long)ffi_closure_ASM; + *(unsigned long*)&tramp[10] = (unsigned long)closure; +#elif defined(__ppc__) + tramp[0] = 0x7c0802a6; // mflr r0 + tramp[1] = 0x429f0005; // bcl 20,31,+0x8 + tramp[2] = 0x7d6802a6; // mflr r11 + tramp[3] = 0x7c0803a6; // mtlr r0 + tramp[4] = 0x818b0018; // lwz r12,24(r11) + tramp[5] = 0x7d8903a6; // mtctr r12 + tramp[6] = 0x816b001c; // lwz r11,28(r11) + tramp[7] = 0x4e800420; // bctr + tramp[8] = (unsigned long)ffi_closure_ASM; + tramp[9] = (unsigned long)closure; +#else +#error undefined architecture +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + // Flush the icache. Only necessary on Darwin. +#if defined(POWERPC_DARWIN) + if (sys_icache_invalidate) { + sys_icache_invalidate(closure->tramp, FFI_TRAMPOLINE_SIZE); + } +#else + flush_range(closure->tramp, FFI_TRAMPOLINE_SIZE); +#endif + + break; + } + + case FFI_AIX: + { + FFI_ASSERT (cif->abi == FFI_AIX); + + ffi_aix_trampoline_struct* tramp_aix = + (ffi_aix_trampoline_struct*)(closure->tramp); + aix_fd* fd = (aix_fd*)(void*)ffi_closure_ASM; + + 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; + break; + } + + default: + return FFI_BAD_ABI; + } + + return FFI_OK; +} + +#if defined(__ppc__) + typedef double ldbits[2]; + + typedef union + { + ldbits lb; + long double ld; + } ldu; +#endif + +/* 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. */ + +#if defined(__ppc__) + ldu temp_ld; +#endif + + double temp; + unsigned int i; + unsigned int nf = 0; /* number of FPRs already used. */ + unsigned int ng = 0; /* number of GPRs already used. */ + ffi_cif* cif = closure->cif; + unsigned int avn = cif->nargs; + void** avalue = alloca(cif->nargs * sizeof(void*)); + ffi_type** arg_types = cif->arg_types; + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ +#if defined(__ppc64__) + if (cif->rtype->type == FFI_TYPE_STRUCT && + ffi64_stret_needs_ptr(cif->rtype, NULL, NULL)) +#elif defined(__ppc__) + if (cif->rtype->type == FFI_TYPE_STRUCT) +#else +#error undefined architecture +#endif + { + rvalue = (void*)*pgr; + pgr++; + ng++; + } + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < avn; i++) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (char*)pgr + MODE_CHOICE(3,7); + ng++; + pgr++; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (char*)pgr + MODE_CHOICE(2,6); + ng++; + pgr++; + break; + +#if defined(__ppc__) + case FFI_TYPE_POINTER: +#endif + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + avalue[i] = (char*)pgr + MODE_CHOICE(0,4); + ng++; + pgr++; + + break; + + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_DARWIN) + { +#if defined(__ppc64__) + unsigned int gprSize = 0; + unsigned int fprSize = 0; + unsigned int savedFPRSize = fprSize; + + avalue[i] = alloca(arg_types[i]->size); + ffi64_struct_to_ram_form(arg_types[i], (const char*)pgr, + &gprSize, (const char*)pfr, &fprSize, &nf, avalue[i], NULL); + + ng += gprSize / sizeof(long); + pgr += gprSize / sizeof(long); + pfr += (fprSize - savedFPRSize) / sizeof(double); + +#elif defined(__ppc__) + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. */ + unsigned int size_al = size_al = arg_types[i]->size; + + /* If the first member of the struct is a double, then align + the struct to double-word. */ + if (arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = ALIGN(arg_types[i]->size, 8); + + if (size_al < 3) + avalue[i] = (char*)pgr + MODE_CHOICE(4,8) - size_al; + else + avalue[i] = (char*)pgr; + + ng += (size_al + 3) / sizeof(long); + pgr += (size_al + 3) / sizeof(long); +#else +#error undefined architecture +#endif + } + + break; + +#if defined(__ppc64__) + case FFI_TYPE_POINTER: +#endif + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* Long long ints are passed in 1 or 2 GPRs. */ + avalue[i] = pgr; + ng += MODE_CHOICE(2,1); + pgr += MODE_CHOICE(2,1); + + break; + + case FFI_TYPE_FLOAT: + /* A float value consumes a GPR. + There are 13 64-bit 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 one or 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 += MODE_CHOICE(2,1); + pgr += MODE_CHOICE(2,1); + + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: +#if defined(__ppc64__) + if (nf < NUM_FPR_ARG_REGISTERS) + { + avalue[i] = pfr; + pfr += 2; + } +#elif defined(__ppc__) + /* A long double value consumes 2/4 GPRs and 2 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 +#error undefined architecture +#endif + else + avalue[i] = pgr; + + nf += 2; + ng += MODE_CHOICE(4,2); + pgr += MODE_CHOICE(4,2); + + break; + +#endif /* FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE */ + + default: + FFI_ASSERT(0); + break; + } + } + + (closure->fun)(cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_ASM to perform return type promotions. */ + return cif->rtype->type; +} + +#if defined(__ppc64__) + +/* ffi64_struct_to_ram_form + + Rebuild a struct's natural layout from buffers of concatenated registers. + Return the number of registers used. + inGPRs[0-7] == r3, inFPRs[0-7] == f1 ... +*/ +void +ffi64_struct_to_ram_form( + const ffi_type* inType, + const char* inGPRs, + unsigned int* ioGPRMarker, + const char* inFPRs, + unsigned int* ioFPRMarker, + unsigned int* ioFPRsUsed, + char* outStruct, // caller-allocated + unsigned int* ioStructMarker) +{ + unsigned int srcGMarker = 0; + unsigned int srcFMarker = 0; + unsigned int savedFMarker = 0; + unsigned int fprsUsed = 0; + unsigned int savedFPRsUsed = 0; + unsigned int destMarker = 0; + + static unsigned int recurseCount = 0; + + if (ioGPRMarker) + srcGMarker = *ioGPRMarker; + + if (ioFPRMarker) + { + srcFMarker = *ioFPRMarker; + savedFMarker = srcFMarker; + } + + if (ioFPRsUsed) + { + fprsUsed = *ioFPRsUsed; + savedFPRsUsed = fprsUsed; + } + + if (ioStructMarker) + destMarker = *ioStructMarker; + + size_t i; + + switch (inType->size) + { + case 1: case 2: case 4: + srcGMarker += 8 - inType->size; + break; + + default: + break; + } + + for (i = 0; inType->elements[i] != NULL; i++) + { + switch (inType->elements[i]->type) + { + case FFI_TYPE_FLOAT: + srcFMarker = ALIGN(srcFMarker, 4); + srcGMarker = ALIGN(srcGMarker, 4); + destMarker = ALIGN(destMarker, 4); + + if (fprsUsed < NUM_FPR_ARG_REGISTERS) + { + *(float*)&outStruct[destMarker] = + (float)*(double*)&inFPRs[srcFMarker]; + srcFMarker += 8; + fprsUsed++; + } + else + *(float*)&outStruct[destMarker] = + (float)*(double*)&inGPRs[srcGMarker]; + + srcGMarker += 4; + destMarker += 4; + + // Skip to next GPR if next element won't fit and we're + // not already at a register boundary. + if (inType->elements[i + 1] != NULL && (destMarker % 8)) + { + if (!FFI_TYPE_1_BYTE(inType->elements[i + 1]->type) && + (!FFI_TYPE_2_BYTE(inType->elements[i + 1]->type) || + (ALIGN(srcGMarker, 8) - srcGMarker) < 2) && + (!FFI_TYPE_4_BYTE(inType->elements[i + 1]->type) || + (ALIGN(srcGMarker, 8) - srcGMarker) < 4)) + srcGMarker = ALIGN(srcGMarker, 8); + } + + break; + + case FFI_TYPE_DOUBLE: + srcFMarker = ALIGN(srcFMarker, 8); + destMarker = ALIGN(destMarker, 8); + + if (fprsUsed < NUM_FPR_ARG_REGISTERS) + { + *(double*)&outStruct[destMarker] = + *(double*)&inFPRs[srcFMarker]; + srcFMarker += 8; + fprsUsed++; + } + else + *(double*)&outStruct[destMarker] = + *(double*)&inGPRs[srcGMarker]; + + destMarker += 8; + + // Skip next GPR + srcGMarker += 8; + srcGMarker = ALIGN(srcGMarker, 8); + + break; + + case FFI_TYPE_LONGDOUBLE: + destMarker = ALIGN(destMarker, 16); + + if (fprsUsed < NUM_FPR_ARG_REGISTERS) + { + srcFMarker = ALIGN(srcFMarker, 8); + srcGMarker = ALIGN(srcGMarker, 8); + *(long double*)&outStruct[destMarker] = + *(long double*)&inFPRs[srcFMarker]; + srcFMarker += 16; + fprsUsed += 2; + } + else + { + srcFMarker = ALIGN(srcFMarker, 16); + srcGMarker = ALIGN(srcGMarker, 16); + *(long double*)&outStruct[destMarker] = + *(long double*)&inGPRs[srcGMarker]; + } + + destMarker += 16; + + // Skip next 2 GPRs + srcGMarker += 16; + srcGMarker = ALIGN(srcGMarker, 8); + + break; + + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + { + if (inType->alignment == 1) // chars only + { + if (inType->size == 1) + outStruct[destMarker++] = inGPRs[srcGMarker++]; + else if (inType->size == 2) + { + outStruct[destMarker++] = inGPRs[srcGMarker++]; + outStruct[destMarker++] = inGPRs[srcGMarker++]; + i++; + } + else + { + memcpy(&outStruct[destMarker], + &inGPRs[srcGMarker], inType->size); + srcGMarker += inType->size; + destMarker += inType->size; + i += inType->size - 1; + } + } + else // chars and other stuff + { + outStruct[destMarker++] = inGPRs[srcGMarker++]; + + // Skip to next GPR if next element won't fit and we're + // not already at a register boundary. + if (inType->elements[i + 1] != NULL && (srcGMarker % 8)) + { + if (!FFI_TYPE_1_BYTE(inType->elements[i + 1]->type) && + (!FFI_TYPE_2_BYTE(inType->elements[i + 1]->type) || + (ALIGN(srcGMarker, 8) - srcGMarker) < 2) && + (!FFI_TYPE_4_BYTE(inType->elements[i + 1]->type) || + (ALIGN(srcGMarker, 8) - srcGMarker) < 4)) + srcGMarker = ALIGN(srcGMarker, inType->alignment); // was 8 + } + } + + break; + } + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + srcGMarker = ALIGN(srcGMarker, 2); + destMarker = ALIGN(destMarker, 2); + + *(short*)&outStruct[destMarker] = + *(short*)&inGPRs[srcGMarker]; + srcGMarker += 2; + destMarker += 2; + + break; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + srcGMarker = ALIGN(srcGMarker, 4); + destMarker = ALIGN(destMarker, 4); + + *(int*)&outStruct[destMarker] = + *(int*)&inGPRs[srcGMarker]; + srcGMarker += 4; + destMarker += 4; + + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + srcGMarker = ALIGN(srcGMarker, 8); + destMarker = ALIGN(destMarker, 8); + + *(long long*)&outStruct[destMarker] = + *(long long*)&inGPRs[srcGMarker]; + srcGMarker += 8; + destMarker += 8; + + break; + + case FFI_TYPE_STRUCT: + recurseCount++; + ffi64_struct_to_ram_form(inType->elements[i], inGPRs, + &srcGMarker, inFPRs, &srcFMarker, &fprsUsed, + outStruct, &destMarker); + recurseCount--; + break; + + default: + FFI_ASSERT(0); // unknown element type + break; + } + } + + srcGMarker = ALIGN(srcGMarker, inType->alignment); + + // Take care of the special case for 16-byte structs, but not for + // nested structs. + if (recurseCount == 0 && srcGMarker == 16) + { + *(long double*)&outStruct[0] = *(long double*)&inGPRs[0]; + srcFMarker = savedFMarker; + fprsUsed = savedFPRsUsed; + } + + if (ioGPRMarker) + *ioGPRMarker = ALIGN(srcGMarker, 8); + + if (ioFPRMarker) + *ioFPRMarker = srcFMarker; + + if (ioFPRsUsed) + *ioFPRsUsed = fprsUsed; + + if (ioStructMarker) + *ioStructMarker = ALIGN(destMarker, 8); +} + +/* ffi64_struct_to_reg_form + + Copy a struct's elements into buffers that can be sliced into registers. + Return the sizes of the output buffers in bytes. Pass NULL buffer pointers + to calculate size only. + outGPRs[0-7] == r3, outFPRs[0-7] == f1 ... +*/ +void +ffi64_struct_to_reg_form( + const ffi_type* inType, + const char* inStruct, + unsigned int* ioStructMarker, + unsigned int* ioFPRsUsed, + char* outGPRs, // caller-allocated + unsigned int* ioGPRSize, + char* outFPRs, // caller-allocated + unsigned int* ioFPRSize) +{ + size_t i; + unsigned int srcMarker = 0; + unsigned int destGMarker = 0; + unsigned int destFMarker = 0; + unsigned int savedFMarker = 0; + unsigned int fprsUsed = 0; + unsigned int savedFPRsUsed = 0; + + static unsigned int recurseCount = 0; + + if (ioStructMarker) + srcMarker = *ioStructMarker; + + if (ioFPRsUsed) + { + fprsUsed = *ioFPRsUsed; + savedFPRsUsed = fprsUsed; + } + + if (ioGPRSize) + destGMarker = *ioGPRSize; + + if (ioFPRSize) + { + destFMarker = *ioFPRSize; + savedFMarker = destFMarker; + } + + switch (inType->size) + { + case 1: case 2: case 4: + destGMarker += 8 - inType->size; + break; + + default: + break; + } + + for (i = 0; inType->elements[i] != NULL; i++) + { + switch (inType->elements[i]->type) + { + // Shadow floating-point types in GPRs for vararg and pre-ANSI + // functions. + case FFI_TYPE_FLOAT: + // Nudge markers to next 4/8-byte boundary + srcMarker = ALIGN(srcMarker, 4); + destGMarker = ALIGN(destGMarker, 4); + destFMarker = ALIGN(destFMarker, 8); + + if (fprsUsed < NUM_FPR_ARG_REGISTERS) + { + if (outFPRs != NULL && inStruct != NULL) + *(double*)&outFPRs[destFMarker] = + (double)*(float*)&inStruct[srcMarker]; + + destFMarker += 8; + fprsUsed++; + } + + if (outGPRs != NULL && inStruct != NULL) + *(double*)&outGPRs[destGMarker] = + (double)*(float*)&inStruct[srcMarker]; + + srcMarker += 4; + destGMarker += 4; + + // Skip to next GPR if next element won't fit and we're + // not already at a register boundary. + if (inType->elements[i + 1] != NULL && (srcMarker % 8)) + { + if (!FFI_TYPE_1_BYTE(inType->elements[i + 1]->type) && + (!FFI_TYPE_2_BYTE(inType->elements[i + 1]->type) || + (ALIGN(destGMarker, 8) - destGMarker) < 2) && + (!FFI_TYPE_4_BYTE(inType->elements[i + 1]->type) || + (ALIGN(destGMarker, 8) - destGMarker) < 4)) + destGMarker = ALIGN(destGMarker, 8); + } + + break; + + case FFI_TYPE_DOUBLE: + srcMarker = ALIGN(srcMarker, 8); + destFMarker = ALIGN(destFMarker, 8); + + if (fprsUsed < NUM_FPR_ARG_REGISTERS) + { + if (outFPRs != NULL && inStruct != NULL) + *(double*)&outFPRs[destFMarker] = + *(double*)&inStruct[srcMarker]; + + destFMarker += 8; + fprsUsed++; + } + + if (outGPRs != NULL && inStruct != NULL) + *(double*)&outGPRs[destGMarker] = + *(double*)&inStruct[srcMarker]; + + srcMarker += 8; + + // Skip next GPR + destGMarker += 8; + destGMarker = ALIGN(destGMarker, 8); + + break; + + case FFI_TYPE_LONGDOUBLE: + srcMarker = ALIGN(srcMarker, 16); + + if (fprsUsed < NUM_FPR_ARG_REGISTERS) + { + destFMarker = ALIGN(destFMarker, 8); + destGMarker = ALIGN(destGMarker, 8); + + if (outFPRs != NULL && inStruct != NULL) + *(long double*)&outFPRs[destFMarker] = + *(long double*)&inStruct[srcMarker]; + + if (outGPRs != NULL && inStruct != NULL) + *(long double*)&outGPRs[destGMarker] = + *(long double*)&inStruct[srcMarker]; + + destFMarker += 16; + fprsUsed += 2; + } + else + { + destGMarker = ALIGN(destGMarker, 16); + + if (outGPRs != NULL && inStruct != NULL) + *(long double*)&outGPRs[destGMarker] = + *(long double*)&inStruct[srcMarker]; + } + + srcMarker += 16; + destGMarker += 16; // Skip next 2 GPRs + destGMarker = ALIGN(destGMarker, 8); // was 16 + + break; + + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + if (inType->alignment == 1) // bytes only + { + if (inType->size == 1) + { + if (outGPRs != NULL && inStruct != NULL) + outGPRs[destGMarker] = inStruct[srcMarker]; + + srcMarker++; + destGMarker++; + } + else if (inType->size == 2) + { + if (outGPRs != NULL && inStruct != NULL) + { + outGPRs[destGMarker] = inStruct[srcMarker]; + outGPRs[destGMarker + 1] = inStruct[srcMarker + 1]; + } + + srcMarker += 2; + destGMarker += 2; + + i++; + } + else + { + if (outGPRs != NULL && inStruct != NULL) + { + // Avoid memcpy for small chunks. + if (inType->size <= sizeof(long)) + *(long*)&outGPRs[destGMarker] = + *(long*)&inStruct[srcMarker]; + else + memcpy(&outGPRs[destGMarker], + &inStruct[srcMarker], inType->size); + } + + srcMarker += inType->size; + destGMarker += inType->size; + i += inType->size - 1; + } + } + else // bytes and other stuff + { + if (outGPRs != NULL && inStruct != NULL) + outGPRs[destGMarker] = inStruct[srcMarker]; + + srcMarker++; + destGMarker++; + + // Skip to next GPR if next element won't fit and we're + // not already at a register boundary. + if (inType->elements[i + 1] != NULL && (destGMarker % 8)) + { + if (!FFI_TYPE_1_BYTE(inType->elements[i + 1]->type) && + (!FFI_TYPE_2_BYTE(inType->elements[i + 1]->type) || + (ALIGN(destGMarker, 8) - destGMarker) < 2) && + (!FFI_TYPE_4_BYTE(inType->elements[i + 1]->type) || + (ALIGN(destGMarker, 8) - destGMarker) < 4)) + destGMarker = ALIGN(destGMarker, inType->alignment); // was 8 + } + } + + break; + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + srcMarker = ALIGN(srcMarker, 2); + destGMarker = ALIGN(destGMarker, 2); + + if (outGPRs != NULL && inStruct != NULL) + *(short*)&outGPRs[destGMarker] = + *(short*)&inStruct[srcMarker]; + + srcMarker += 2; + destGMarker += 2; + + if (inType->elements[i + 1] == NULL) + destGMarker = ALIGN(destGMarker, inType->alignment); + + break; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + srcMarker = ALIGN(srcMarker, 4); + destGMarker = ALIGN(destGMarker, 4); + + if (outGPRs != NULL && inStruct != NULL) + *(int*)&outGPRs[destGMarker] = + *(int*)&inStruct[srcMarker]; + + srcMarker += 4; + destGMarker += 4; + + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + srcMarker = ALIGN(srcMarker, 8); + destGMarker = ALIGN(destGMarker, 8); + + if (outGPRs != NULL && inStruct != NULL) + *(long long*)&outGPRs[destGMarker] = + *(long long*)&inStruct[srcMarker]; + + srcMarker += 8; + destGMarker += 8; + + if (inType->elements[i + 1] == NULL) + destGMarker = ALIGN(destGMarker, inType->alignment); + + break; + + case FFI_TYPE_STRUCT: + recurseCount++; + ffi64_struct_to_reg_form(inType->elements[i], + inStruct, &srcMarker, &fprsUsed, outGPRs, + &destGMarker, outFPRs, &destFMarker); + recurseCount--; + break; + + default: + FFI_ASSERT(0); + break; + } + } + + destGMarker = ALIGN(destGMarker, inType->alignment); + + // Take care of the special case for 16-byte structs, but not for + // nested structs. + if (recurseCount == 0 && destGMarker == 16) + { + if (outGPRs != NULL && inStruct != NULL) + *(long double*)&outGPRs[0] = *(long double*)&inStruct[0]; + + destFMarker = savedFMarker; + fprsUsed = savedFPRsUsed; + } + + if (ioStructMarker) + *ioStructMarker = ALIGN(srcMarker, 8); + + if (ioFPRsUsed) + *ioFPRsUsed = fprsUsed; + + if (ioGPRSize) + *ioGPRSize = ALIGN(destGMarker, 8); + + if (ioFPRSize) + *ioFPRSize = ALIGN(destFMarker, 8); +} + +/* ffi64_stret_needs_ptr + + Determine whether a returned struct needs a pointer in r3 or can fit + in registers. +*/ + +bool +ffi64_stret_needs_ptr( + const ffi_type* inType, + unsigned short* ioGPRCount, + unsigned short* ioFPRCount) +{ + // Obvious case first- struct is larger than combined FPR size. + if (inType->size > 14 * 8) + return true; + + // Now the struct can physically fit in registers, determine if it + // also fits logically. + bool needsPtr = false; + unsigned short gprsUsed = 0; + unsigned short fprsUsed = 0; + size_t i; + + if (ioGPRCount) + gprsUsed = *ioGPRCount; + + if (ioFPRCount) + fprsUsed = *ioFPRCount; + + for (i = 0; inType->elements[i] != NULL && !needsPtr; i++) + { + switch (inType->elements[i]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + gprsUsed++; + fprsUsed++; + + if (fprsUsed > 13) + needsPtr = true; + + break; + + case FFI_TYPE_LONGDOUBLE: + gprsUsed += 2; + fprsUsed += 2; + + if (fprsUsed > 14) + needsPtr = true; + + break; + + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + { + gprsUsed++; + + if (gprsUsed > 8) + { + needsPtr = true; + break; + } + + if (inType->elements[i + 1] == NULL) // last byte in the struct + break; + + // Count possible contiguous bytes ahead, up to 8. + unsigned short j; + + for (j = 1; j < 8; j++) + { + if (inType->elements[i + j] == NULL || + !FFI_TYPE_1_BYTE(inType->elements[i + j]->type)) + break; + } + + i += j - 1; // allow for i++ before the test condition + + break; + } + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + gprsUsed++; + + if (gprsUsed > 8) + needsPtr = true; + + break; + + case FFI_TYPE_STRUCT: + needsPtr = ffi64_stret_needs_ptr( + inType->elements[i], &gprsUsed, &fprsUsed); + + break; + + default: + FFI_ASSERT(0); + break; + } + } + + if (ioGPRCount) + *ioGPRCount = gprsUsed; + + if (ioFPRCount) + *ioFPRCount = fprsUsed; + + return needsPtr; +} + +/* ffi64_data_size + + Calculate the size in bytes of an ffi type. +*/ + +unsigned int +ffi64_data_size( + const ffi_type* inType) +{ + unsigned int size = 0; + + switch (inType->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + size = 1; + break; + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + size = 2; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_FLOAT: + size = 4; + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_DOUBLE: + size = 8; + break; + + case FFI_TYPE_LONGDOUBLE: + size = 16; + break; + + case FFI_TYPE_STRUCT: + ffi64_struct_to_reg_form( + inType, NULL, NULL, NULL, NULL, &size, NULL, NULL); + break; + + case FFI_TYPE_VOID: + break; + + default: + FFI_ASSERT(0); + break; + } + + return size; +} + +#endif /* defined(__ppc64__) */ +#endif /* __ppc__ || __ppc64__ */ diff --git a/Modules/_ctypes/libffi_osx/powerpc/ppc64-darwin_closure.S b/Modules/_ctypes/libffi_osx/powerpc/ppc64-darwin_closure.S new file mode 100644 index 0000000..248d43a --- /dev/null +++ b/Modules/_ctypes/libffi_osx/powerpc/ppc64-darwin_closure.S @@ -0,0 +1,423 @@ +#if defined(__ppc64__) + +/* ----------------------------------------------------------------------- + darwin_closure.S - Copyright (c) 2002, 2003, 2004, Free Software Foundation, + Inc. based on ppc_closure.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM + +#include <ffi.h> +#include <ppc-ffitarget.h> // for FFI_TRAMPOLINE_SIZE +#include <ppc-darwin.h> +#include <architecture/ppc/mode_independent_asm.h> + + .file "ppc64-darwin_closure.S" +.text + .align LOG2_GPR_BYTES + .globl _ffi_closure_ASM + +.text + .align LOG2_GPR_BYTES + +_ffi_closure_ASM: +LFB1: + mflr r0 + stg r0,SF_RETURN(r1) // save return address + + // Save GPRs 3 - 10 (aligned to 8) in the parents outgoing area. + stg r3,SF_ARG1(r1) + stg r4,SF_ARG2(r1) + stg r5,SF_ARG3(r1) + stg r6,SF_ARG4(r1) + stg r7,SF_ARG5(r1) + stg r8,SF_ARG6(r1) + stg r9,SF_ARG7(r1) + stg r10,SF_ARG8(r1) + +LCFI0: +/* 48 bytes (Linkage Area) + 64 bytes (outgoing parameter area, always reserved) + 112 bytes (14*8 for incoming FPR) + ? bytes (result) + 112 bytes (14*8 for outgoing FPR) + 16 bytes (2 saved registers) + 352 + ? total bytes +*/ + + std r31,-8(r1) // Save registers we use. + std r30,-16(r1) + mr r30,r1 // Save the old SP. + mr r31,r11 // Save the ffi_closure around ffi64_data_size. + + // Calculate the space we need. + stdu r1,-SF_MINSIZE(r1) + ld r3,FFI_TRAMPOLINE_SIZE(r31) // ffi_closure->cif* + ld r3,16(r3) // ffi_cif->rtype* + bl Lffi64_data_size$stub + ld r1,0(r1) + + addi r3,r3,352 // Add our overhead. + neg r3,r3 + li r0,-32 // Align to 32 bytes. + and r3,r3,r0 + stdux r1,r1,r3 // Grow the stack. + + mr r11,r31 // Copy the ffi_closure back. + +LCFI1: + // We want to build up an area for the parameters passed + // in registers. (both floating point and integer) + +/* 320 bytes (callee stack frame aligned to 32) + 48 bytes (caller linkage area) + 368 (start of caller parameter area aligned to 8) +*/ + + // Save FPRs 1 - 14. (aligned to 8) + stfd f1,112(r1) + stfd f2,120(r1) + stfd f3,128(r1) + stfd f4,136(r1) + stfd f5,144(r1) + stfd f6,152(r1) + stfd f7,160(r1) + stfd f8,168(r1) + stfd f9,176(r1) + stfd f10,184(r1) + stfd f11,192(r1) + stfd f12,200(r1) + stfd f13,208(r1) + stfd f14,216(r1) + + // Set up registers for the routine that actually does the work. + mr r3,r11 // context pointer from the trampoline + addi r4,r1,224 // result storage + addi r5,r30,SF_ARG1 // saved GPRs + addi r6,r1,112 // saved FPRs + bl Lffi_closure_helper_DARWIN$stub + + // Look the proper starting point in table + // by using return type as an offset. + addi r5,r1,224 // 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 + +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,4(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_FLOAT +Lret_type2: + lfs f1,0(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_DOUBLE +Lret_type3: + lfd f1,0(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_LONGDOUBLE +Lret_type4: + lfd f1,0(r5) + lfd f2,8(r5) + b Lfinish + nop + +// case FFI_TYPE_UINT8 +Lret_type5: + lbz r3,7(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_SINT8 +Lret_type6: + lbz r3,7(r5) + extsb r3,r3 + b Lfinish + nop + +// case FFI_TYPE_UINT16 +Lret_type7: + lhz r3,6(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_SINT16 +Lret_type8: + lha r3,6(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_UINT32 +Lret_type9: // same as Lret_type1 + lwz r3,4(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_SINT32 +Lret_type10: // same as Lret_type1 + lwz r3,4(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_UINT64 +Lret_type11: + ld r3,0(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_SINT64 +Lret_type12: // same as Lret_type11 + ld r3,0(r5) + b Lfinish + nop + nop + +// case FFI_TYPE_STRUCT +Lret_type13: + b Lret_struct + nop + nop + nop + +// ** End 16-byte aligned cases ** +// case FFI_TYPE_POINTER +// This case assumes that FFI_TYPE_POINTER == FFI_TYPE_LAST. If more types +// are added in future, the following code will need to be updated and +// padded to 16 bytes. +Lret_type14: + lg r3,0(r5) + b Lfinish + +// copy struct into registers +Lret_struct: + ld r31,FFI_TRAMPOLINE_SIZE(r31) // ffi_closure->cif* + ld r3,16(r31) // ffi_cif->rtype* + ld r31,24(r31) // ffi_cif->flags + mr r4,r5 // copy struct* to 2nd arg + addi r7,r1,SF_ARG9 // GPR return area + addi r9,r30,-16-(14*8) // FPR return area + li r5,0 // struct offset ptr (NULL) + li r6,0 // FPR used count ptr (NULL) + li r8,0 // GPR return area size ptr (NULL) + li r10,0 // FPR return area size ptr (NULL) + bl Lffi64_struct_to_reg_form$stub + + // Load GPRs + ld r3,SF_ARG9(r1) + ld r4,SF_ARG10(r1) + ld r5,SF_ARG11(r1) + ld r6,SF_ARG12(r1) + nop + ld r7,SF_ARG13(r1) + ld r8,SF_ARG14(r1) + ld r9,SF_ARG15(r1) + ld r10,SF_ARG16(r1) + nop + + // Load FPRs + mtcrf 0x2,r31 + bf 26,Lfinish + lfd f1,-16-(14*8)(r30) + lfd f2,-16-(13*8)(r30) + lfd f3,-16-(12*8)(r30) + lfd f4,-16-(11*8)(r30) + nop + lfd f5,-16-(10*8)(r30) + lfd f6,-16-(9*8)(r30) + lfd f7,-16-(8*8)(r30) + lfd f8,-16-(7*8)(r30) + nop + lfd f9,-16-(6*8)(r30) + lfd f10,-16-(5*8)(r30) + lfd f11,-16-(4*8)(r30) + lfd f12,-16-(3*8)(r30) + nop + lfd f13,-16-(2*8)(r30) + lfd f14,-16-(1*8)(r30) + // Fall through + +// case done +Lfinish: + lg r1,0(r1) // Restore stack pointer. + ld r31,-8(r1) // Restore registers we used. + ld r30,-16(r1) + lg r0,SF_RETURN(r1) // Get return address. + mtlr r0 // Reset link register. + blr + +// END(ffi_closure_ASM) + +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 ; Length of Common Information Entry +LSCIE1: + .long 0x0 ; CIE Identifier Tag + .byte 0x1 ; CIE Version + .ascii "zR\0" ; CIE Augmentation + .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor + .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x90 ; FDE Encoding (indirect pcrel) + .byte 0xc ; DW_CFA_def_cfa + .byte 0x1 ; uleb128 0x1 + .byte 0x0 ; uleb128 0x0 + .align LOG2_GPR_BYTES +LECIE1: +.globl _ffi_closure_ASM.eh +_ffi_closure_ASM.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 ; FDE Length + +LASFDE1: + .long LASFDE1-EH_frame1 ; FDE CIE offset + .g_long LLFB1$non_lazy_ptr-. ; FDE initial location + .set L$set$3,LFE1-LFB1 + .g_long L$set$3 ; FDE address range + .byte 0x0 ; uleb128 0x0; Augmentation size + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$3,LCFI1-LCFI0 + .long L$set$3 + .byte 0xe ; DW_CFA_def_cfa_offset + .byte 176,1 ; uleb128 176 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-LFB1 + .long L$set$4 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .align LOG2_GPR_BYTES + +LEFDE1: +.data + .align LOG2_GPR_BYTES +LDFCM0: +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align LOG2_GPR_BYTES + +Lffi_closure_helper_DARWIN$stub: + .indirect_symbol _ffi_closure_helper_DARWIN + mflr r0 + bcl 20,31,LO$ffi_closure_helper_DARWIN + +LO$ffi_closure_helper_DARWIN: + mflr r11 + addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN) + mtlr r0 + lgu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)(r11) + mtctr r12 + bctr + +.lazy_symbol_pointer +L_ffi_closure_helper_DARWIN$lazy_ptr: + .indirect_symbol _ffi_closure_helper_DARWIN + .g_long dyld_stub_binding_helper + +.data + .align LOG2_GPR_BYTES +LLFB1$non_lazy_ptr: + .g_long LFB1 + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align LOG2_GPR_BYTES + +Lffi64_struct_to_reg_form$stub: + .indirect_symbol _ffi64_struct_to_reg_form + mflr r0 + bcl 20,31,LO$ffi64_struct_to_reg_form + +LO$ffi64_struct_to_reg_form: + mflr r11 + addis r11,r11,ha16(L_ffi64_struct_to_reg_form$lazy_ptr - LO$ffi64_struct_to_reg_form) + mtlr r0 + lgu r12,lo16(L_ffi64_struct_to_reg_form$lazy_ptr - LO$ffi64_struct_to_reg_form)(r11) + mtctr r12 + bctr + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align LOG2_GPR_BYTES + +Lffi64_data_size$stub: + .indirect_symbol _ffi64_data_size + mflr r0 + bcl 20,31,LO$ffi64_data_size + +LO$ffi64_data_size: + mflr r11 + addis r11,r11,ha16(L_ffi64_data_size$lazy_ptr - LO$ffi64_data_size) + mtlr r0 + lgu r12,lo16(L_ffi64_data_size$lazy_ptr - LO$ffi64_data_size)(r11) + mtctr r12 + bctr + +.lazy_symbol_pointer +L_ffi64_struct_to_reg_form$lazy_ptr: + .indirect_symbol _ffi64_struct_to_reg_form + .g_long dyld_stub_binding_helper + +L_ffi64_data_size$lazy_ptr: + .indirect_symbol _ffi64_data_size + .g_long dyld_stub_binding_helper + +#endif // __ppc64__ diff --git a/Modules/_ctypes/libffi_osx/types.c b/Modules/_ctypes/libffi_osx/types.c new file mode 100644 index 0000000..44806ae --- /dev/null +++ b/Modules/_ctypes/libffi_osx/types.c @@ -0,0 +1,115 @@ +/* ----------------------------------------------------------------------- + types.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Predefined ffi_types needed by libffi. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +/* Type definitions */ +#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) \ + ffi_type ffi_type_##n = { s, a, t, NULL } +#define FFI_AGGREGATE_TYPEDEF(n, e) \ + ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e } + +FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8); +FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8); +FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); +FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); +FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); +FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); +FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); + +/* Size and alignment are fake here. They must not be 0. */ +FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID); + +#if defined ALPHA || defined SPARC64 || defined X86_64 || \ + defined S390X || defined IA64 || defined POWERPC64 +FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); +#else +FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); +#endif + +#if defined X86 || defined ARM || defined M68K || defined(X86_DARWIN) + +# ifdef X86_64 + FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); + FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); +# else + FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); + FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); +# endif + +#elif defined(POWERPC_DARWIN) +FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); +#elif defined SH +FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); +#else +FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); +#endif + +#if defined X86 || defined X86_WIN32 || defined M68K || defined(X86_DARWIN) + +# if defined X86_WIN32 || defined X86_64 + FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +# else + FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); +# endif + +# ifdef X86_DARWIN + FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); +# else + FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); +# endif + +#elif defined ARM || defined SH || defined POWERPC_AIX +FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); +#elif defined POWERPC_DARWIN +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); + +# if __GNUC__ >= 4 + FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); +# else + FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); +# endif + +#elif defined SPARC +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); + +# ifdef SPARC64 + FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); +# else + FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); +# endif + +#elif defined X86_64 || defined POWERPC64 +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); +#else +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); +#endif
\ No newline at end of file diff --git a/Modules/_ctypes/libffi_osx/x86/darwin64.S b/Modules/_ctypes/libffi_osx/x86/darwin64.S new file mode 100644 index 0000000..eba451e --- /dev/null +++ b/Modules/_ctypes/libffi_osx/x86/darwin64.S @@ -0,0 +1,415 @@ +/* ----------------------------------------------------------------------- + darwin64.S - Copyright (c) 2006 Free Software Foundation, Inc. + derived from unix64.S + + x86-64 Foreign Function Interface for Darwin. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifdef __x86_64__ +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .file "darwin64.S" +.text + +/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)()); + + Bit o trickiness here -- ARGS+BYTES is the base of the stack frame + for this function. This has been allocated by ffi_call. We also + deallocate some of the stack that has been alloca'd. */ + + .align 3 + .globl _ffi_call_unix64 + +_ffi_call_unix64: +LUW0: + movq (%rsp), %r10 /* Load return address. */ + leaq (%rdi, %rsi), %rax /* Find local stack base. */ + movq %rdx, (%rax) /* Save flags. */ + movq %rcx, 8(%rax) /* Save raddr. */ + movq %rbp, 16(%rax) /* Save old frame pointer. */ + movq %r10, 24(%rax) /* Relocate return address. */ + movq %rax, %rbp /* Finalize local stack frame. */ +LUW1: + movq %rdi, %r10 /* Save a copy of the register area. */ + movq %r8, %r11 /* Save a copy of the target fn. */ + movl %r9d, %eax /* Set number of SSE registers. */ + + /* Load up all argument registers. */ + movq (%r10), %rdi + movq 8(%r10), %rsi + movq 16(%r10), %rdx + movq 24(%r10), %rcx + movq 32(%r10), %r8 + movq 40(%r10), %r9 + testl %eax, %eax + jnz Lload_sse +Lret_from_load_sse: + + /* Deallocate the reg arg area. */ + leaq 176(%r10), %rsp + + /* Call the user function. */ + call *%r11 + + /* Deallocate stack arg area; local stack frame in redzone. */ + leaq 24(%rbp), %rsp + + movq 0(%rbp), %rcx /* Reload flags. */ + movq 8(%rbp), %rdi /* Reload raddr. */ + movq 16(%rbp), %rbp /* Reload old frame pointer. */ +LUW2: + + /* The first byte of the flags contains the FFI_TYPE. */ + movzbl %cl, %r10d + leaq Lstore_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + +Lstore_table: + .long Lst_void-Lstore_table /* FFI_TYPE_VOID */ + .long Lst_sint32-Lstore_table /* FFI_TYPE_INT */ + .long Lst_float-Lstore_table /* FFI_TYPE_FLOAT */ + .long Lst_double-Lstore_table /* FFI_TYPE_DOUBLE */ + .long Lst_ldouble-Lstore_table /* FFI_TYPE_LONGDOUBLE */ + .long Lst_uint8-Lstore_table /* FFI_TYPE_UINT8 */ + .long Lst_sint8-Lstore_table /* FFI_TYPE_SINT8 */ + .long Lst_uint16-Lstore_table /* FFI_TYPE_UINT16 */ + .long Lst_sint16-Lstore_table /* FFI_TYPE_SINT16 */ + .long Lst_uint32-Lstore_table /* FFI_TYPE_UINT32 */ + .long Lst_sint32-Lstore_table /* FFI_TYPE_SINT32 */ + .long Lst_int64-Lstore_table /* FFI_TYPE_UINT64 */ + .long Lst_int64-Lstore_table /* FFI_TYPE_SINT64 */ + .long Lst_struct-Lstore_table /* FFI_TYPE_STRUCT */ + .long Lst_int64-Lstore_table /* FFI_TYPE_POINTER */ + + .text + .align 3 +Lst_void: + ret + .align 3 +Lst_uint8: + movzbq %al, %rax + movq %rax, (%rdi) + ret + .align 3 +Lst_sint8: + movsbq %al, %rax + movq %rax, (%rdi) + ret + .align 3 +Lst_uint16: + movzwq %ax, %rax + movq %rax, (%rdi) + .align 3 +Lst_sint16: + movswq %ax, %rax + movq %rax, (%rdi) + ret + .align 3 +Lst_uint32: + movl %eax, %eax + movq %rax, (%rdi) + .align 3 +Lst_sint32: + cltq + movq %rax, (%rdi) + ret + .align 3 +Lst_int64: + movq %rax, (%rdi) + ret + .align 3 +Lst_float: + movss %xmm0, (%rdi) + ret + .align 3 +Lst_double: + movsd %xmm0, (%rdi) + ret +Lst_ldouble: + fstpt (%rdi) + ret + .align 3 +Lst_struct: + leaq -20(%rsp), %rsi /* Scratch area in redzone. */ + + /* We have to locate the values now, and since we don't want to + write too much data into the user's return value, we spill the + value to a 16 byte scratch area first. Bits 8, 9, and 10 + control where the values are located. Only one of the three + bits will be set; see ffi_prep_cif_machdep for the pattern. */ + movd %xmm0, %r10 + movd %xmm1, %r11 + testl $0x100, %ecx + cmovnz %rax, %rdx + cmovnz %r10, %rax + testl $0x200, %ecx + cmovnz %r10, %rdx + testl $0x400, %ecx + cmovnz %r10, %rax + cmovnz %r11, %rdx + movq %rax, (%rsi) + movq %rdx, 8(%rsi) + + /* Bits 12-31 contain the true size of the structure. Copy from + the scratch area to the true destination. */ + shrl $12, %ecx + rep movsb + ret + + /* Many times we can avoid loading any SSE registers at all. + It's not worth an indirect jump to load the exact set of + SSE registers needed; zero or all is a good compromise. */ + .align 3 +LUW3: +Lload_sse: + movdqa 48(%r10), %xmm0 + movdqa 64(%r10), %xmm1 + movdqa 80(%r10), %xmm2 + movdqa 96(%r10), %xmm3 + movdqa 112(%r10), %xmm4 + movdqa 128(%r10), %xmm5 + movdqa 144(%r10), %xmm6 + movdqa 160(%r10), %xmm7 + jmp Lret_from_load_sse + +LUW4: + .align 3 + .globl _ffi_closure_unix64 + +_ffi_closure_unix64: +LUW5: + /* The carry flag is set by the trampoline iff SSE registers + are used. Don't clobber it before the branch instruction. */ + leaq -200(%rsp), %rsp +LUW6: + movq %rdi, (%rsp) + movq %rsi, 8(%rsp) + movq %rdx, 16(%rsp) + movq %rcx, 24(%rsp) + movq %r8, 32(%rsp) + movq %r9, 40(%rsp) + jc Lsave_sse +Lret_from_save_sse: + + movq %r10, %rdi + leaq 176(%rsp), %rsi + movq %rsp, %rdx + leaq 208(%rsp), %rcx + call _ffi_closure_unix64_inner + + /* Deallocate stack frame early; return value is now in redzone. */ + addq $200, %rsp +LUW7: + + /* The first byte of the return value contains the FFI_TYPE. */ + movzbl %al, %r10d + leaq Lload_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + +Lload_table: + .long Lld_void-Lload_table /* FFI_TYPE_VOID */ + .long Lld_int32-Lload_table /* FFI_TYPE_INT */ + .long Lld_float-Lload_table /* FFI_TYPE_FLOAT */ + .long Lld_double-Lload_table /* FFI_TYPE_DOUBLE */ + .long Lld_ldouble-Lload_table /* FFI_TYPE_LONGDOUBLE */ + .long Lld_int8-Lload_table /* FFI_TYPE_UINT8 */ + .long Lld_int8-Lload_table /* FFI_TYPE_SINT8 */ + .long Lld_int16-Lload_table /* FFI_TYPE_UINT16 */ + .long Lld_int16-Lload_table /* FFI_TYPE_SINT16 */ + .long Lld_int32-Lload_table /* FFI_TYPE_UINT32 */ + .long Lld_int32-Lload_table /* FFI_TYPE_SINT32 */ + .long Lld_int64-Lload_table /* FFI_TYPE_UINT64 */ + .long Lld_int64-Lload_table /* FFI_TYPE_SINT64 */ + .long Lld_struct-Lload_table /* FFI_TYPE_STRUCT */ + .long Lld_int64-Lload_table /* FFI_TYPE_POINTER */ + + .text + .align 3 +Lld_void: + ret + .align 3 +Lld_int8: + movzbl -24(%rsp), %eax + ret + .align 3 +Lld_int16: + movzwl -24(%rsp), %eax + ret + .align 3 +Lld_int32: + movl -24(%rsp), %eax + ret + .align 3 +Lld_int64: + movq -24(%rsp), %rax + ret + .align 3 +Lld_float: + movss -24(%rsp), %xmm0 + ret + .align 3 +Lld_double: + movsd -24(%rsp), %xmm0 + ret + .align 3 +Lld_ldouble: + fldt -24(%rsp) + ret + .align 3 +Lld_struct: + /* There are four possibilities here, %rax/%rdx, %xmm0/%rax, + %rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading + both rdx and xmm1 with the second word. For the remaining, + bit 8 set means xmm0 gets the second word, and bit 9 means + that rax gets the second word. */ + movq -24(%rsp), %rcx + movq -16(%rsp), %rdx + movq -16(%rsp), %xmm1 + testl $0x100, %eax + cmovnz %rdx, %rcx + movd %rcx, %xmm0 + testl $0x200, %eax + movq -24(%rsp), %rax + cmovnz %rdx, %rax + ret + + /* See the comment above Lload_sse; the same logic applies here. */ + .align 3 +LUW8: +Lsave_sse: + movdqa %xmm0, 48(%rsp) + movdqa %xmm1, 64(%rsp) + movdqa %xmm2, 80(%rsp) + movdqa %xmm3, 96(%rsp) + movdqa %xmm4, 112(%rsp) + movdqa %xmm5, 128(%rsp) + movdqa %xmm6, 144(%rsp) + movdqa %xmm7, 160(%rsp) + jmp Lret_from_save_sse + +LUW9: +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 /* CIE Length */ + .long L$set$0 +LSCIE1: + .long 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ + .ascii "zR\0" /* CIE Augmentation */ + .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x78 /* sleb128 -8; CIE Data Alignment Factor */ + .byte 0x10 /* CIE RA Column */ + .byte 0x1 /* uleb128 0x1; Augmentation size */ + .byte 0x10 /* FDE Encoding (pcrel sdata4) */ + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .byte 0x7 /* uleb128 0x7 */ + .byte 0x8 /* uleb128 0x8 */ + .byte 0x90 /* DW_CFA_offset, column 0x10 */ + .byte 0x1 + .align 3 +LECIE1: + .globl _ffi_call_unix64.eh +_ffi_call_unix64.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 /* FDE Length */ + .long L$set$1 +LASFDE1: + .long LASFDE1-EH_frame1 /* FDE CIE offset */ + .quad LUW0-. /* FDE initial location */ + .set L$set$2,LUW4-LUW0 /* FDE address range */ + .quad L$set$2 + .byte 0x0 /* Augmentation size */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$3,LUW1-LUW0 + .long L$set$3 + + /* New stack frame based off rbp. This is a itty bit of unwind + trickery in that the CFA *has* changed. There is no easy way + to describe it correctly on entry to the function. Fortunately, + it doesn't matter too much since at all points we can correctly + unwind back to ffi_call. Note that the location to which we + moved the return address is (the new) CFA-8, so from the + perspective of the unwind info, it hasn't moved. */ + .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */ + .byte 0x6 + .byte 0x20 + .byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */ + .byte 0x2 + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$4,LUW2-LUW1 + .long L$set$4 + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .byte 0x7 + .byte 0x8 + .byte 0xc0+6 /* DW_CFA_restore, %rbp */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$5,LUW3-LUW2 + .long L$set$5 + .byte 0xb /* DW_CFA_restore_state */ + + .align 3 +LEFDE1: + .globl _ffi_closure_unix64.eh +_ffi_closure_unix64.eh: +LSFDE3: + .set L$set$6,LEFDE3-LASFDE3 /* FDE Length */ + .long L$set$6 +LASFDE3: + .long LASFDE3-EH_frame1 /* FDE CIE offset */ + .quad LUW5-. /* FDE initial location */ + .set L$set$7,LUW9-LUW5 /* FDE address range */ + .quad L$set$7 + .byte 0x0 /* Augmentation size */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$8,LUW6-LUW5 + .long L$set$8 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 208,1 /* uleb128 208 */ + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$9,LUW7-LUW6 + .long L$set$9 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$10,LUW8-LUW7 + .long L$set$10 + .byte 0xb /* DW_CFA_restore_state */ + + .align 3 +LEFDE3: + .subsections_via_symbols + +#endif /* __x86_64__ */ diff --git a/Modules/_ctypes/libffi_osx/x86/x86-darwin.S b/Modules/_ctypes/libffi_osx/x86/x86-darwin.S new file mode 100644 index 0000000..d91bdc0 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/x86/x86-darwin.S @@ -0,0 +1,243 @@ +#ifdef __i386__ +/* ----------------------------------------------------------------------- + darwin.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. + ----------------------------------------------------------------------- */ + +/* + * This file is based on sysv.S and then hacked up by Ronald who hasn't done + * assembly programming in 8 years. + */ + +#ifndef __x86_64__ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#ifdef PyObjC_STRICT_DEBUGGING + /* XXX: Debugging of stack alignment, to be removed */ +#define ASSERT_STACK_ALIGNED movdqa -16(%esp), %xmm0 +#else +#define ASSERT_STACK_ALIGNED +#endif + +.text + +.globl _ffi_prep_args + +.align 4 +.globl _ffi_call_SYSV + +_ffi_call_SYSV: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp + subl $8,%esp + ASSERT_STACK_ALIGNED +.LCFI1: + /* Make room for all of the new args. */ + movl 16(%ebp),%ecx + subl %ecx,%esp + + ASSERT_STACK_ALIGNED + + movl %esp,%eax + + /* Place all of the ffi_prep_args in position */ + subl $8,%esp + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + ASSERT_STACK_ALIGNED + + /* Return stack to previous state and call the function */ + addl $16,%esp + + ASSERT_STACK_ALIGNED + + call *28(%ebp) + + /* XXX: return returns return with 'ret $4', that upsets the stack! */ + movl 16(%ebp),%ecx + addl %ecx,%esp + + + /* Load %ecx with the return type code */ + movl 20(%ebp),%ecx + + + /* If the return value pointer is NULL, assume no return value. */ + cmpl $0,24(%ebp) + jne retint + + /* Even if there is no space for the return value, we are + obliged to handle floating-point values. */ + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +retint: + cmpl $FFI_TYPE_INT,%ecx + jne retfloat + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp epilogue + +retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne retdouble + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne retlongdouble + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne retint64 + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne retstruct1b + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + jmp epilogue + +retstruct1b: + cmpl $FFI_TYPE_SINT8,%ecx + jne retstruct2b + movl 24(%ebp),%ecx + movb %al,0(%ecx) + jmp epilogue + +retstruct2b: + cmpl $FFI_TYPE_SINT16,%ecx + jne retstruct + movl 24(%ebp),%ecx + movw %ax,0(%ecx) + jmp epilogue + +retstruct: + cmpl $FFI_TYPE_STRUCT,%ecx + jne noretval + /* Nothing to do! */ + + subl $4,%esp + + ASSERT_STACK_ALIGNED + + addl $8,%esp + movl %ebp, %esp + popl %ebp + ret + +noretval: +epilogue: + ASSERT_STACK_ALIGNED + addl $8, %esp + + + movl %ebp,%esp + popl %ebp + ret +.LFE1: +.ffi_call_SYSV_end: +#if 0 + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV +#endif + +#if 0 + .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 + +#endif /* ifndef __x86_64__ */ + +#endif /* defined __i386__ */ diff --git a/Modules/_ctypes/libffi_osx/x86/x86-ffi64.c b/Modules/_ctypes/libffi_osx/x86/x86-ffi64.c new file mode 100644 index 0000000..ac37fb7 --- /dev/null +++ b/Modules/_ctypes/libffi_osx/x86/x86-ffi64.c @@ -0,0 +1,624 @@ +#ifdef __x86_64__ + +/* ----------------------------------------------------------------------- + x86-ffi64.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de> + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <stdarg.h> + +#define MAX_GPR_REGS 6 +#define MAX_SSE_REGS 8 + +typedef struct RegisterArgs { + /* Registers for argument passing. */ + UINT64 gpr[MAX_GPR_REGS]; + __int128_t sse[MAX_SSE_REGS]; +} RegisterArgs; + +extern void +ffi_call_unix64( + void* args, + unsigned long bytes, + unsigned flags, + void* raddr, + void (*fnaddr)(), + unsigned ssecount); + +/* All reference to register classes here is identical to the code in + gcc/config/i386/i386.c. Do *not* change one without the other. */ + +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the exception + of SSESF, SSEDF classes, that are basically SSE class, just gcc will + use SF or DFmode move instead of DImode to avoid reformating penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). */ +enum x86_64_reg_class +{ + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_COMPLEX_X87_CLASS, + X86_64_MEMORY_CLASS +}; + +#define MAX_CLASSES 4 +#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS) + +/* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ +static enum x86_64_reg_class +merge_classes( + enum x86_64_reg_class class1, + enum x86_64_reg_class class2) +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, + MEMORY is used. */ + if (class1 == X86_64_X87_CLASS + || class1 == X86_64_X87UP_CLASS + || class1 == X86_64_COMPLEX_X87_CLASS + || class2 == X86_64_X87_CLASS + || class2 == X86_64_X87UP_CLASS + || class2 == X86_64_COMPLEX_X87_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + See the x86-64 PS ABI for details. */ + +static int +classify_argument( + ffi_type* type, + enum x86_64_reg_class classes[], + size_t byte_offset) +{ + switch (type->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + if (byte_offset + type->size <= 4) + classes[0] = X86_64_INTEGERSI_CLASS; + else + classes[0] = X86_64_INTEGER_CLASS; + + return 1; + + case FFI_TYPE_FLOAT: + if (byte_offset == 0) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + + return 1; + + case FFI_TYPE_DOUBLE: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + + case FFI_TYPE_LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2; + + case FFI_TYPE_STRUCT: + { + ffi_type** ptr; + int i; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + const int UNITS_PER_WORD = 8; + int words = + (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + /* 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++) + { + byte_offset = ALIGN(byte_offset, (*ptr)->alignment); + + int num = classify_argument(*ptr, subclasses, byte_offset % 8); + + if (num == 0) + return 0; + + int pos = byte_offset / 8; + + for (i = 0; i < num; i++) + { + 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 if 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 n = classify_argument(type, classes, 0); + int ngpr = 0; + int nsse = 0; + int i; + + if (n == 0) + return 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 = 0; + int ssecount = 0; + int flags = cif->rtype->type; + int i, avn, n, ngpr, nsse; + enum x86_64_reg_class classes[MAX_CLASSES]; + size_t bytes; + + if (flags != FFI_TYPE_VOID) + { + n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + + if (n == 0) + { + /* The return value is passed in memory. A pointer to that + memory is the first argument. Allocate a register for it. */ + gprcount++; + + /* We don't have to do anything in asm for the return. */ + flags = FFI_TYPE_VOID; + } + else if (flags == FFI_TYPE_STRUCT) + { + /* Mark which registers the result appears in. */ + _Bool sse0 = SSE_CLASS_P(classes[0]); + _Bool sse1 = n == 2 && SSE_CLASS_P(classes[1]); + + if (sse0 && !sse1) + flags |= 1 << 8; + else if (!sse0 && sse1) + flags |= 1 << 9; + else if (sse0 && sse1) + flags |= 1 << 10; + + /* Mark the true size of the structure. */ + flags |= cif->rtype->size << 12; + } + } + + /* Go over all arguments and determine the way they should be passed. + If it's in a register and there is space for it, let that be so. If + not, add it's size to the stack byte count. */ + for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++) + { + if (examine_argument(cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = cif->arg_types[i]->alignment; + + if (align < 8) + align = 8; + + bytes = ALIGN(bytes, align); + bytes += cif->arg_types[i]->size; + } + else + { + gprcount += ngpr; + ssecount += nsse; + } + } + + if (ssecount) + flags |= 1 << 11; + + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +void +ffi_call( + ffi_cif* cif, + void (*fn)(), + void* rvalue, + void** avalue) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + char* stack; + char* argp; + ffi_type** arg_types; + int gprcount, ssecount, ngpr, nsse, i, avn; + _Bool ret_in_memory; + RegisterArgs* reg_args; + + /* Can't call 32-bit mode from 64-bit mode. */ + FFI_ASSERT(cif->abi == FFI_UNIX64); + + /* If the return value is a struct and we don't have a return value + address then we need to make one. Note the setting of flags to + VOID above in ffi_prep_cif_machdep. */ + ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT + && (cif->flags & 0xff) == FFI_TYPE_VOID); + + if (rvalue == NULL && ret_in_memory) + rvalue = alloca (cif->rtype->size); + + /* Allocate the space for the arguments, plus 4 words of temp space. */ + stack = alloca(sizeof(RegisterArgs) + cif->bytes + 4 * 8); + reg_args = (RegisterArgs*)stack; + argp = stack + sizeof(RegisterArgs); + + 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(RegisterArgs), + cif->flags, rvalue, fn, ssecount); +} + +extern void ffi_closure_unix64(void); + +ffi_status +ffi_prep_closure( + ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void* user_data) +{ + if (cif->abi != FFI_UNIX64) + return FFI_BAD_ABI; + + volatile unsigned short* tramp = + (volatile unsigned short*)&closure->tramp[0]; + + tramp[0] = 0xbb49; /* mov <code>, %r11 */ + *(void* volatile*)&tramp[1] = ffi_closure_unix64; + tramp[5] = 0xba49; /* mov <data>, %r10 */ + *(void* volatile*)&tramp[6] = closure; + + /* Set the carry bit if the function uses any sse registers. + This is clc or stc, together with the first byte of the jmp. */ + tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8; + tramp[11] = 0xe3ff; /* jmp *%r11 */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +int +ffi_closure_unix64_inner( + ffi_closure* closure, + void* rvalue, + RegisterArgs* reg_args, + char* argp) +{ + ffi_cif* cif = closure->cif; + void** avalue = alloca(cif->nargs * sizeof(void *)); + ffi_type** arg_types; + long i, avn; + int gprcount = 0; + int ssecount = 0; + int ngpr, nsse; + int ret; + + 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 !defined(X86_DARWIN) + /* 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; + } + } +#endif + + /* 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__ */ diff --git a/Modules/_ctypes/libffi_osx/x86/x86-ffi_darwin.c b/Modules/_ctypes/libffi_osx/x86/x86-ffi_darwin.c new file mode 100644 index 0000000..ce8687d --- /dev/null +++ b/Modules/_ctypes/libffi_osx/x86/x86-ffi_darwin.c @@ -0,0 +1,569 @@ +#ifdef __i386__ +/* ----------------------------------------------------------------------- + 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> + +//void ffi_prep_args(char *stack, extended_cif *ecif); + +static inline int +retval_on_stack( + ffi_type* tp) +{ + if (tp->type == FFI_TYPE_STRUCT) + { +// int size = tp->size; + + if (tp->size > 8) + return 1; + + switch (tp->size) + { + case 1: case 2: case 4: case 8: + return 0; + default: + return 1; + } + } + + return 0; +} + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ +/*@-exportheader@*/ +extern void ffi_prep_args(char*, extended_cif*); +void +ffi_prep_args( + char* stack, + extended_cif* ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void** p_argv = ecif->avalue; + register char* argp = stack; + register ffi_type** p_arg; + + if (retval_on_stack(ecif->cif->rtype)) + { + *(void**)argp = ecif->rvalue; + argp += 4; + } + + p_arg = ecif->cif->arg_types; + + for (i = ecif->cif->nargs; i > 0; i--, p_arg++, p_argv++) + { + size_t z = (*p_arg)->size; + + /* Align if necessary */ + if ((sizeof(int) - 1) & (unsigned)argp) + argp = (char*)ALIGN(argp, sizeof(int)); + + 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); + break; + } + } + else + memcpy(argp, *p_argv, z); + + argp += z; + } +} + +/* Perform machine dependent cif processing */ +ffi_status +ffi_prep_cif_machdep( + ffi_cif* cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { +#if !defined(X86_WIN32) && !defined(X86_DARWIN) + case FFI_TYPE_STRUCT: +#endif + case FFI_TYPE_VOID: + 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; + +#if defined(X86_WIN32) || defined(X86_DARWIN) + case FFI_TYPE_STRUCT: + switch (cif->rtype->size) + { + case 1: + cif->flags = FFI_TYPE_SINT8; + break; + + case 2: + cif->flags = FFI_TYPE_SINT16; + break; + + case 4: + cif->flags = FFI_TYPE_INT; + break; + + case 8: + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_STRUCT; + break; + } + + break; +#endif + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + /* Darwin: The stack needs to be aligned to a multiple of 16 bytes */ + cif->bytes = (cif->bytes + 15) & ~0xF; + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void +ffi_call_SYSV( + void (*)(char *, extended_cif *), +/*@out@*/ extended_cif* , + unsigned , + unsigned , +/*@out@*/ unsigned* , + void (*fn)(void)); +/*@=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)(void)); +/*@=declundef@*/ +/*@=exportheader@*/ +#endif /* X86_WIN32 */ + +void +ffi_call( +/*@dependent@*/ ffi_cif* cif, + void (*fn)(void), +/*@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) && retval_on_stack(cif->rtype)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + /* To avoid changing the assembly code make sure the size of the argument + block is a multiple of 16. Then add 8 to compensate for local variables + in ffi_call_SYSV. */ + 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_closure_SYSV( + ffi_closure* closure) __attribute__((regparm(1))); + +#if !FFI_NO_RAW_API +static void +ffi_closure_raw_SYSV( + ffi_raw_closure* closure) __attribute__((regparm(1))); +#endif + +/*@-exportheader@*/ +static inline +void +ffi_prep_incoming_args_SYSV( + char* stack, + void** rvalue, + void** avalue, + ffi_cif* cif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void** p_argv = avalue; + register char* argp = stack; + register ffi_type** p_arg; + + if (retval_on_stack(cif->rtype)) + { + *rvalue = *(void**)argp; + argp += 4; + } + + for (i = cif->nargs, p_arg = cif->arg_types; i > 0; i--, p_arg++, p_argv++) + { +// 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; + + argp += (*p_arg)->size; + } +} + +/* This function is jumped to by the trampoline */ +__attribute__((regparm(1))) +static void +ffi_closure_SYSV( + ffi_closure* closure) +{ + long double res; + ffi_cif* cif = closure->cif; + void** arg_area = (void**)alloca(cif->nargs * sizeof(void*)); + void* resp = (void*)&res; + void* args = __builtin_dwarf_cfa(); + + /* 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 reset 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); + + /* now, do a generic return based on the value of rtype */ + if (cif->flags == FFI_TYPE_INT) + asm("movl (%0),%%eax" + : : "r" (resp) : "eax"); + else if (cif->flags == FFI_TYPE_FLOAT) + asm("flds (%0)" + : : "r" (resp) : "st"); + else if (cif->flags == FFI_TYPE_DOUBLE) + asm("fldl (%0)" + : : "r" (resp) : "st", "st(1)"); + else if (cif->flags == FFI_TYPE_LONGDOUBLE) + asm("fldt (%0)" + : : "r" (resp) : "st", "st(1)"); + else if (cif->flags == FFI_TYPE_SINT64) + asm("movl 0(%0),%%eax;" + "movl 4(%0),%%edx" + : : "r" (resp) + : "eax", "edx"); + +#if defined(X86_WIN32) || defined(X86_DARWIN) + else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct */ + asm("movsbl (%0),%%eax" + : : "r" (resp) : "eax"); + else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */ + asm("movswl (%0),%%eax" + : : "r" (resp) : "eax"); +#endif + + else if (cif->flags == FFI_TYPE_STRUCT) + asm("lea -8(%ebp),%esp;" + "pop %esi;" + "pop %edi;" + "pop %ebp;" + "ret $4"); +} + + +/* 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); + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + FFI_INIT_TRAMPOLINE(closure->tramp, &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 + +__attribute__((regparm(1))) +static void +ffi_closure_raw_SYSV( + ffi_raw_closure* closure) +{ + long double res; + ffi_raw* raw_args = (ffi_raw*)__builtin_dwarf_cfa(); + ffi_cif* cif = closure->cif; + unsigned short rtype = cif->flags; + void* resp = (void*)&res; + + (closure->fun)(cif, resp, raw_args, closure->user_data); + + /* 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) +{ +// FFI_ASSERT (cif->abi == FFI_SYSV); + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + int i; + +/* 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, &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) && retval_on_stack(cif->rtype)) + { + /*@-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 // !FFI_NO_RAW_API +//#endif // !__x86_64__ +#endif // __i386__ |