====================CC-PDDC==================== Doug Lea and released to the public domain, as explained at http://creativecommons.org/licenses/publicdomain. Send questions, ====================COPYRIGHT==================== Copyright (C) 1998 Geoffrey Keating Copyright (C) 2001 John Hornkvist Copyright (C) 2002, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. ====================COPYRIGHT==================== Copyright (C) 2003-2004, 2006, 2009-2017 Free Software Foundation, Inc. ====================COPYRIGHT==================== aix.S - Copyright (c) 2002, 2009 Free Software Foundation, Inc. based on darwin.S by John Hornkvist ====================COPYRIGHT==================== aix_closure.S - Copyright (c) 2002, 2003, 2009 Free Software Foundation, Inc. based on darwin_closure.S ====================COPYRIGHT==================== asm.h - Copyright (c) 1998 Geoffrey Keating ====================COPYRIGHT==================== closures.c - Copyright (c) 2019 Anthony Green Copyright (c) 2007, 2009, 2010 Red Hat, Inc. Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc Copyright (c) 2011 Plausible Labs Cooperative, Inc. ====================COPYRIGHT==================== darwin.S - Copyright (c) 2000 John Hornkvist Copyright (c) 2004, 2010 Free Software Foundation, Inc. ====================COPYRIGHT==================== darwin_closure.S - Copyright (c) 2002, 2003, 2004, 2010, Free Software Foundation, Inc. based on ppc_closure.S ====================COPYRIGHT==================== ffi.c - Copyright (C) 2013 IBM Copyright (C) 2011 Anthony Green Copyright (C) 2011 Kyle Moffett Copyright (C) 2008 Red Hat, Inc Copyright (C) 2007, 2008 Free Software Foundation, Inc Copyright (c) 1998 Geoffrey Keating ====================COPYRIGHT==================== ffi.c - Copyright (c) 2011 Timothy Wall Copyright (c) 2011 Plausible Labs Cooperative, Inc. Copyright (c) 2011 Anthony Green Copyright (c) 2011 Free Software Foundation Copyright (c) 1998, 2008, 2011 Red Hat, Inc. ====================COPYRIGHT==================== ffi.c - Copyright (c) 2017 Anthony Green Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc. Copyright (c) 2002 Ranjit Mathew Copyright (c) 2002 Bo Thorsen Copyright (c) 2002 Roger Sayle Copyright (C) 2008, 2010 Free Software Foundation, Inc. ====================COPYRIGHT==================== ffi64.c - Copyright (c) 2011, 2018 Anthony Green Copyright (c) 2013 The Written Word, Inc. Copyright (c) 2008, 2010 Red Hat, Inc. Copyright (c) 2002, 2007 Bo Thorsen ====================COPYRIGHT==================== ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc Copyright (c) 1996-2003 Red Hat, Inc. ====================COPYRIGHT==================== ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (c) 2010 CodeSourcery Copyright (c) 1996-2003 Red Hat, Inc. ====================COPYRIGHT==================== ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, Inc. ====================COPYRIGHT==================== ffiw64.c - Copyright (c) 2018 Anthony Green Copyright (c) 2014 Red Hat, Inc. ====================COPYRIGHT==================== java_raw_api.c - Copyright (c) 1999, 2007, 2008 Red Hat, Inc. ====================COPYRIGHT==================== libffi 3.3 - Copyright (c) 2011, 2014, 2019 Anthony Green - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. ====================COPYRIGHT==================== prep_cif.c - Copyright (c) 2011, 2012 Anthony Green Copyright (c) 1996, 1998, 2007 Red Hat, Inc. ====================COPYRIGHT==================== raw_api.c - Copyright (c) 1999, 2008 Red Hat, Inc. ====================COPYRIGHT==================== sysv.S - Copyright (c) 1998 Geoffrey Keating Copyright (C) 2007 Free Software Foundation, Inc ====================COPYRIGHT==================== sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc. Copyright (c) 2011 Plausible Labs Cooperative, Inc. Copyright (c) 2019 Microsoft Corporation. ====================COPYRIGHT==================== sysv.S - Copyright (c) 2017 Anthony Green - Copyright (c) 2013 The Written Word, Inc. - Copyright (c) 1996,1998,2001-2003,2005,2008,2010 Red Hat, Inc. ====================COPYRIGHT==================== sysv.h - Copyright (c) 2003 Jakub Jelinek Copyright (c) 2008 Red Hat, Inc. ====================COPYRIGHT==================== types.c - Copyright (c) 1996, 1998 Red Hat, Inc. ====================COPYRIGHT==================== unix64.S - Copyright (c) 2013 The Written Word, Inc. - Copyright (c) 2008 Red Hat, Inc - Copyright (c) 2002 Bo Thorsen ====================COPYRIGHT==================== Copyright 1993 Bill Triggs Copyright 1995-2017 Bruno Haible ====================COPYRIGHT==================== Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies ====================COPYRIGHT==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. ====================COPYRIGHT==================== libffi - Copyright (c) 1996-2019 Anthony Green, Red Hat, Inc and others. See source files for details. ====================COPYRIGHT==================== programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. ====================File: .yandex_meta/files/configs/aarch64-apple-iphoneos/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: .yandex_meta/files/configs/aarch64-apple-macos/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: .yandex_meta/files/configs/aarch64-unknown-linux-android21/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: .yandex_meta/files/configs/aarch64-unknown-linux-gnu/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: .yandex_meta/files/configs/armv7a-unknown-linux-androideabi16/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (c) 2010 CodeSourcery Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_VFP, FFI_LAST_ABI, #if defined(__ARM_PCS_VFP) || defined(_M_ARM) FFI_DEFAULT_ABI = FFI_VFP, #else FFI_DEFAULT_ABI = FFI_SYSV, #endif } ffi_abi; #endif #define FFI_EXTRA_CIF_FIELDS \ int vfp_used; \ unsigned short vfp_reg_free, vfp_nargs; \ signed char vfp_args[16] \ #define FFI_TARGET_SPECIFIC_VARIADIC #ifndef _M_ARM #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 #else #error "No trampoline table implementation" #endif #else #ifdef _MSC_VER #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_FUNCTION 12 #else #define FFI_TRAMPOLINE_SIZE 12 #endif #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #endif ====================File: .yandex_meta/files/configs/armv7a-unknown-linux-gnueabihf/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (c) 2010 CodeSourcery Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_VFP, FFI_LAST_ABI, #if defined(__ARM_PCS_VFP) || defined(_M_ARM) FFI_DEFAULT_ABI = FFI_VFP, #else FFI_DEFAULT_ABI = FFI_SYSV, #endif } ffi_abi; #endif #define FFI_EXTRA_CIF_FIELDS \ int vfp_used; \ unsigned short vfp_reg_free, vfp_nargs; \ signed char vfp_args[16] \ #define FFI_TARGET_SPECIFIC_VARIADIC #ifndef _M_ARM #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 #else #error "No trampoline table implementation" #endif #else #ifdef _MSC_VER #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_FUNCTION 12 #else #define FFI_TRAMPOLINE_SIZE 12 #endif #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #endif ====================File: .yandex_meta/files/configs/i386-microsoft-windows/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) /* 4 bytes of ENDBR64 + 7 bytes of LEA + 6 bytes of JMP + 7 bytes of NOP + 8 bytes of pointer. */ # define FFI_TRAMPOLINE_SIZE 32 # define FFI_NATIVE_RAW_API 0 #else /* 4 bytes of ENDBR32 + 5 bytes of MOV + 5 bytes of JMP + 2 unused bytes. */ # define FFI_TRAMPOLINE_SIZE 16 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #if !defined(GENERATE_LIBFFI_MAP) && defined(__ASSEMBLER__) \ && defined(__CET__) # include # define _CET_NOTRACK notrack #else # define _CET_ENDBR # define _CET_NOTRACK #endif #endif ====================File: .yandex_meta/files/configs/i686-pc-linux-android16/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: .yandex_meta/files/configs/powerpc64le-unknown-linux-gnu/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ #if defined (POWERPC) && defined (__powerpc64__) /* linux64 */ #ifndef POWERPC64 #define POWERPC64 #endif #elif defined (POWERPC_DARWIN) && defined (__ppc64__) /* Darwin64 */ #ifndef POWERPC64 #define POWERPC64 #endif #ifndef POWERPC_DARWIN64 #define POWERPC_DARWIN64 #endif #elif defined (POWERPC_AIX) && defined (__64BIT__) /* AIX64 */ #ifndef POWERPC64 #define POWERPC64 #endif #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, #if defined (POWERPC_AIX) FFI_AIX, FFI_DARWIN, FFI_DEFAULT_ABI = FFI_AIX, FFI_LAST_ABI #elif defined (POWERPC_DARWIN) FFI_AIX, FFI_DARWIN, FFI_DEFAULT_ABI = FFI_DARWIN, FFI_LAST_ABI #else /* The FFI_COMPAT values are used by old code. Since libffi may be a shared library we have to support old values for backwards compatibility. */ FFI_COMPAT_SYSV, FFI_COMPAT_GCC_SYSV, FFI_COMPAT_LINUX64, FFI_COMPAT_LINUX, FFI_COMPAT_LINUX_SOFT_FLOAT, # if defined (POWERPC64) /* This bit, always set in new code, must not be set in any of the old FFI_COMPAT values that might be used for 64-bit linux. We only need worry about FFI_COMPAT_LINUX64, but to be safe avoid all old values. */ FFI_LINUX = 8, /* This and following bits can reuse FFI_COMPAT values. */ FFI_LINUX_STRUCT_ALIGN = 1, FFI_LINUX_LONG_DOUBLE_128 = 2, FFI_LINUX_LONG_DOUBLE_IEEE128 = 4, FFI_DEFAULT_ABI = (FFI_LINUX # ifdef __STRUCT_PARM_ALIGN__ | FFI_LINUX_STRUCT_ALIGN # endif # ifdef __LONG_DOUBLE_128__ | FFI_LINUX_LONG_DOUBLE_128 # ifdef __LONG_DOUBLE_IEEE128__ | FFI_LINUX_LONG_DOUBLE_IEEE128 # endif # endif ), FFI_LAST_ABI = 16 # else /* This bit, always set in new code, must not be set in any of the old FFI_COMPAT values that might be used for 32-bit linux/sysv/bsd. */ FFI_SYSV = 8, /* This and following bits can reuse FFI_COMPAT values. */ FFI_SYSV_SOFT_FLOAT = 1, FFI_SYSV_STRUCT_RET = 2, FFI_SYSV_IBM_LONG_DOUBLE = 4, FFI_SYSV_LONG_DOUBLE_128 = 16, FFI_DEFAULT_ABI = (FFI_SYSV # ifdef __NO_FPRS__ | FFI_SYSV_SOFT_FLOAT # endif # if (defined (__SVR4_STRUCT_RETURN) \ || defined (POWERPC_FREEBSD) && !defined (__AIX_STRUCT_RETURN)) | FFI_SYSV_STRUCT_RET # endif # if __LDBL_MANT_DIG__ == 106 | FFI_SYSV_IBM_LONG_DOUBLE # endif # ifdef __LONG_DOUBLE_128__ | FFI_SYSV_LONG_DOUBLE_128 # endif ), FFI_LAST_ABI = 32 # endif #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (POWERPC) || defined (POWERPC_FREEBSD) # define FFI_GO_CLOSURES 1 # define FFI_TARGET_SPECIFIC_VARIADIC 1 # define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs #endif #if defined (POWERPC_AIX) # define FFI_GO_CLOSURES 1 #endif /* ppc_closure.S and linux64_closure.S expect this. */ #define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER /* We define additional types below. If generic types are added that must be supported by powerpc libffi then it is likely that FFI_PPC_TYPE_LAST needs increasing *and* the jump tables in ppc_closure.S and linux64_closure.S be extended. */ #if !(FFI_TYPE_LAST == FFI_PPC_TYPE_LAST \ || (FFI_TYPE_LAST == FFI_TYPE_COMPLEX \ && !defined FFI_TARGET_HAS_COMPLEX_TYPE)) # error "You likely have a broken powerpc libffi" #endif /* Needed for soft-float long-double-128 support. */ #define FFI_TYPE_UINT128 (FFI_PPC_TYPE_LAST + 1) /* Needed for FFI_SYSV small structure returns. */ #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2) /* Used by ELFv2 for homogenous structure returns. */ #define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1) #define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2) #define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3) #define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4) #define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5) #if _CALL_ELF == 2 # define FFI_TRAMPOLINE_SIZE 32 #else # if defined(POWERPC64) || defined(POWERPC_AIX) # if defined(POWERPC_DARWIN64) # define FFI_TRAMPOLINE_SIZE 48 # else # define FFI_TRAMPOLINE_SIZE 24 # endif # else /* POWERPC || POWERPC_AIX */ # define FFI_TRAMPOLINE_SIZE 40 # endif #endif #ifndef LIBFFI_ASM #if defined(POWERPC_DARWIN) || defined(POWERPC_AIX) struct ffi_aix_trampoline_struct { void * code_pointer; /* Pointer to ffi_closure_ASM */ void * toc; /* TOC */ void * static_chain; /* Pointer to closure */ }; #endif #endif #endif ====================File: .yandex_meta/files/configs/x86_64-apple-iphonesimulator/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: .yandex_meta/files/configs/x86_64-apple-macosx/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: .yandex_meta/files/configs/x86_64-microsoft-windows/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) /* 4 bytes of ENDBR64 + 7 bytes of LEA + 6 bytes of JMP + 7 bytes of NOP + 8 bytes of pointer. */ # define FFI_TRAMPOLINE_SIZE 32 # define FFI_NATIVE_RAW_API 0 #else /* 4 bytes of ENDBR32 + 5 bytes of MOV + 5 bytes of JMP + 2 unused bytes. */ # define FFI_TRAMPOLINE_SIZE 16 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #if !defined(GENERATE_LIBFFI_MAP) && defined(__ASSEMBLER__) \ && defined(__CET__) # include # define _CET_NOTRACK notrack #else # define _CET_ENDBR # define _CET_NOTRACK #endif #endif ====================File: .yandex_meta/files/configs/x86_64-pc-linux-android21/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: configs/aarch64-apple-iphoneos/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: configs/aarch64-apple-macos/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: configs/aarch64-unknown-linux-android21/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: configs/aarch64-unknown-linux-gnu/include/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: configs/armv7a-unknown-linux-androideabi16/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (c) 2010 CodeSourcery Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_VFP, FFI_LAST_ABI, #if defined(__ARM_PCS_VFP) || defined(_M_ARM) FFI_DEFAULT_ABI = FFI_VFP, #else FFI_DEFAULT_ABI = FFI_SYSV, #endif } ffi_abi; #endif #define FFI_EXTRA_CIF_FIELDS \ int vfp_used; \ unsigned short vfp_reg_free, vfp_nargs; \ signed char vfp_args[16] \ #define FFI_TARGET_SPECIFIC_VARIADIC #ifndef _M_ARM #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 #else #error "No trampoline table implementation" #endif #else #ifdef _MSC_VER #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_FUNCTION 12 #else #define FFI_TRAMPOLINE_SIZE 12 #endif #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #endif ====================File: configs/armv7a-unknown-linux-gnueabihf/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (c) 2010 CodeSourcery Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_VFP, FFI_LAST_ABI, #if defined(__ARM_PCS_VFP) || defined(_M_ARM) FFI_DEFAULT_ABI = FFI_VFP, #else FFI_DEFAULT_ABI = FFI_SYSV, #endif } ffi_abi; #endif #define FFI_EXTRA_CIF_FIELDS \ int vfp_used; \ unsigned short vfp_reg_free, vfp_nargs; \ signed char vfp_args[16] \ #define FFI_TARGET_SPECIFIC_VARIADIC #ifndef _M_ARM #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 #else #error "No trampoline table implementation" #endif #else #ifdef _MSC_VER #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_FUNCTION 12 #else #define FFI_TRAMPOLINE_SIZE 12 #endif #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #endif ====================File: configs/i386-microsoft-windows/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) /* 4 bytes of ENDBR64 + 7 bytes of LEA + 6 bytes of JMP + 7 bytes of NOP + 8 bytes of pointer. */ # define FFI_TRAMPOLINE_SIZE 32 # define FFI_NATIVE_RAW_API 0 #else /* 4 bytes of ENDBR32 + 5 bytes of MOV + 5 bytes of JMP + 2 unused bytes. */ # define FFI_TRAMPOLINE_SIZE 16 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #if !defined(GENERATE_LIBFFI_MAP) && defined(__ASSEMBLER__) \ && defined(__CET__) # include # define _CET_NOTRACK notrack #else # define _CET_ENDBR # define _CET_NOTRACK #endif #endif ====================File: configs/i686-pc-linux-android16/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: configs/powerpc64le-unknown-linux-gnu/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ #if defined (POWERPC) && defined (__powerpc64__) /* linux64 */ #ifndef POWERPC64 #define POWERPC64 #endif #elif defined (POWERPC_DARWIN) && defined (__ppc64__) /* Darwin64 */ #ifndef POWERPC64 #define POWERPC64 #endif #ifndef POWERPC_DARWIN64 #define POWERPC_DARWIN64 #endif #elif defined (POWERPC_AIX) && defined (__64BIT__) /* AIX64 */ #ifndef POWERPC64 #define POWERPC64 #endif #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, #if defined (POWERPC_AIX) FFI_AIX, FFI_DARWIN, FFI_DEFAULT_ABI = FFI_AIX, FFI_LAST_ABI #elif defined (POWERPC_DARWIN) FFI_AIX, FFI_DARWIN, FFI_DEFAULT_ABI = FFI_DARWIN, FFI_LAST_ABI #else /* The FFI_COMPAT values are used by old code. Since libffi may be a shared library we have to support old values for backwards compatibility. */ FFI_COMPAT_SYSV, FFI_COMPAT_GCC_SYSV, FFI_COMPAT_LINUX64, FFI_COMPAT_LINUX, FFI_COMPAT_LINUX_SOFT_FLOAT, # if defined (POWERPC64) /* This bit, always set in new code, must not be set in any of the old FFI_COMPAT values that might be used for 64-bit linux. We only need worry about FFI_COMPAT_LINUX64, but to be safe avoid all old values. */ FFI_LINUX = 8, /* This and following bits can reuse FFI_COMPAT values. */ FFI_LINUX_STRUCT_ALIGN = 1, FFI_LINUX_LONG_DOUBLE_128 = 2, FFI_LINUX_LONG_DOUBLE_IEEE128 = 4, FFI_DEFAULT_ABI = (FFI_LINUX # ifdef __STRUCT_PARM_ALIGN__ | FFI_LINUX_STRUCT_ALIGN # endif # ifdef __LONG_DOUBLE_128__ | FFI_LINUX_LONG_DOUBLE_128 # ifdef __LONG_DOUBLE_IEEE128__ | FFI_LINUX_LONG_DOUBLE_IEEE128 # endif # endif ), FFI_LAST_ABI = 16 # else /* This bit, always set in new code, must not be set in any of the old FFI_COMPAT values that might be used for 32-bit linux/sysv/bsd. */ FFI_SYSV = 8, /* This and following bits can reuse FFI_COMPAT values. */ FFI_SYSV_SOFT_FLOAT = 1, FFI_SYSV_STRUCT_RET = 2, FFI_SYSV_IBM_LONG_DOUBLE = 4, FFI_SYSV_LONG_DOUBLE_128 = 16, FFI_DEFAULT_ABI = (FFI_SYSV # ifdef __NO_FPRS__ | FFI_SYSV_SOFT_FLOAT # endif # if (defined (__SVR4_STRUCT_RETURN) \ || defined (POWERPC_FREEBSD) && !defined (__AIX_STRUCT_RETURN)) | FFI_SYSV_STRUCT_RET # endif # if __LDBL_MANT_DIG__ == 106 | FFI_SYSV_IBM_LONG_DOUBLE # endif # ifdef __LONG_DOUBLE_128__ | FFI_SYSV_LONG_DOUBLE_128 # endif ), FFI_LAST_ABI = 32 # endif #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (POWERPC) || defined (POWERPC_FREEBSD) # define FFI_GO_CLOSURES 1 # define FFI_TARGET_SPECIFIC_VARIADIC 1 # define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs #endif #if defined (POWERPC_AIX) # define FFI_GO_CLOSURES 1 #endif /* ppc_closure.S and linux64_closure.S expect this. */ #define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER /* We define additional types below. If generic types are added that must be supported by powerpc libffi then it is likely that FFI_PPC_TYPE_LAST needs increasing *and* the jump tables in ppc_closure.S and linux64_closure.S be extended. */ #if !(FFI_TYPE_LAST == FFI_PPC_TYPE_LAST \ || (FFI_TYPE_LAST == FFI_TYPE_COMPLEX \ && !defined FFI_TARGET_HAS_COMPLEX_TYPE)) # error "You likely have a broken powerpc libffi" #endif /* Needed for soft-float long-double-128 support. */ #define FFI_TYPE_UINT128 (FFI_PPC_TYPE_LAST + 1) /* Needed for FFI_SYSV small structure returns. */ #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2) /* Used by ELFv2 for homogenous structure returns. */ #define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1) #define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2) #define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3) #define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4) #define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5) #if _CALL_ELF == 2 # define FFI_TRAMPOLINE_SIZE 32 #else # if defined(POWERPC64) || defined(POWERPC_AIX) # if defined(POWERPC_DARWIN64) # define FFI_TRAMPOLINE_SIZE 48 # else # define FFI_TRAMPOLINE_SIZE 24 # endif # else /* POWERPC || POWERPC_AIX */ # define FFI_TRAMPOLINE_SIZE 40 # endif #endif #ifndef LIBFFI_ASM #if defined(POWERPC_DARWIN) || defined(POWERPC_AIX) struct ffi_aix_trampoline_struct { void * code_pointer; /* Pointer to ffi_closure_ASM */ void * toc; /* TOC */ void * static_chain; /* Pointer to closure */ }; #endif #endif #endif ====================File: configs/x86_64-apple-iphonesimulator/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: configs/x86_64-apple-macosx/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: configs/x86_64-microsoft-windows/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) /* 4 bytes of ENDBR64 + 7 bytes of LEA + 6 bytes of JMP + 7 bytes of NOP + 8 bytes of pointer. */ # define FFI_TRAMPOLINE_SIZE 32 # define FFI_NATIVE_RAW_API 0 #else /* 4 bytes of ENDBR32 + 5 bytes of MOV + 5 bytes of JMP + 2 unused bytes. */ # define FFI_TRAMPOLINE_SIZE 16 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #if !defined(GENERATE_LIBFFI_MAP) && defined(__ASSEMBLER__) \ && defined(__CET__) # include # define _CET_NOTRACK notrack #else # define _CET_ENDBR # define _CET_NOTRACK #endif #endif ====================File: configs/x86_64-pc-linux-android21/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: configs/x86_64-pc-linux-gnu/include/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: src/aarch64/ffi.c==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if defined(__aarch64__) || defined(__arm64__)|| defined (_M_ARM64) #include #include #include #include #include #include #include "internal.h" #ifdef _M_ARM64 #include /* FlushInstructionCache */ #endif /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; all further uses in this file will refer to the 128-bit type. */ #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE # if FFI_TYPE_LONGDOUBLE != 4 # error FFI_TYPE_LONGDOUBLE out of date # endif #else # undef FFI_TYPE_LONGDOUBLE # define FFI_TYPE_LONGDOUBLE 4 #endif union _d { UINT64 d; UINT32 s[2]; }; struct _v { union _d d[2] __attribute__((aligned(16))); }; struct call_context { struct _v v[N_V_ARG_REG]; UINT64 x[N_X_ARG_REG]; }; #if FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #include #endif #else #if defined (__clang__) && defined (__APPLE__) extern void sys_icache_invalidate (void *start, size_t len); #endif static inline void ffi_clear_cache (void *start, void *end) { #if defined (__clang__) && defined (__APPLE__) sys_icache_invalidate (start, (char *)end - (char *)start); #elif defined (__GNUC__) __builtin___clear_cache (start, end); #elif defined (_M_ARM64) FlushInstructionCache(GetCurrentProcess(), start, (char*)end - (char*)start); #else #error "Missing builtin to flush instruction cache" #endif } #endif /* A subroutine of is_vfp_type. Given a structure type, return the type code of the first non-structure element. Recurse for structure elements. Return -1 if the structure is in fact empty, i.e. no nested elements. */ static int is_hfa0 (const ffi_type *ty) { ffi_type **elements = ty->elements; int i, ret = -1; if (elements != NULL) for (i = 0; elements[i]; ++i) { ret = elements[i]->type; if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX) { ret = is_hfa0 (elements[i]); if (ret < 0) continue; } break; } return ret; } /* A subroutine of is_vfp_type. Given a structure type, return true if all of the non-structure elements are the same as CANDIDATE. */ static int is_hfa1 (const ffi_type *ty, int candidate) { ffi_type **elements = ty->elements; int i; if (elements != NULL) for (i = 0; elements[i]; ++i) { int t = elements[i]->type; if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) { if (!is_hfa1 (elements[i], candidate)) return 0; } else if (t != candidate) return 0; } return 1; } /* Determine if TY may be allocated to the FP registers. This is both an fp scalar type as well as an homogenous floating point aggregate (HFA). That is, a structure consisting of 1 to 4 members of all the same type, where that type is an fp scalar. Returns non-zero iff TY is an HFA. The result is the AARCH64_RET_* constant for the type. */ static int is_vfp_type (const ffi_type *ty) { ffi_type **elements; int candidate, i; size_t size, ele_count; /* Quickest tests first. */ candidate = ty->type; switch (candidate) { default: return 0; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: ele_count = 1; goto done; case FFI_TYPE_COMPLEX: candidate = ty->elements[0]->type; switch (candidate) { case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: ele_count = 2; goto done; } return 0; case FFI_TYPE_STRUCT: break; } /* No HFA types are smaller than 4 bytes, or larger than 64 bytes. */ size = ty->size; if (size < 4 || size > 64) return 0; /* Find the type of the first non-structure member. */ elements = ty->elements; candidate = elements[0]->type; if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX) { for (i = 0; ; ++i) { candidate = is_hfa0 (elements[i]); if (candidate >= 0) break; } } /* If the first member is not a floating point type, it's not an HFA. Also quickly re-check the size of the structure. */ switch (candidate) { case FFI_TYPE_FLOAT: ele_count = size / sizeof(float); if (size != ele_count * sizeof(float)) return 0; break; case FFI_TYPE_DOUBLE: ele_count = size / sizeof(double); if (size != ele_count * sizeof(double)) return 0; break; case FFI_TYPE_LONGDOUBLE: ele_count = size / sizeof(long double); if (size != ele_count * sizeof(long double)) return 0; break; default: return 0; } if (ele_count > 4) return 0; /* Finally, make sure that all scalar elements are the same type. */ for (i = 0; elements[i]; ++i) { int t = elements[i]->type; if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) { if (!is_hfa1 (elements[i], candidate)) return 0; } else if (t != candidate) return 0; } /* All tests succeeded. Encode the result. */ done: return candidate * 4 + (4 - (int)ele_count); } /* Representation of the procedure call argument marshalling state. The terse state variable names match the names used in the AARCH64 PCS. */ struct arg_state { unsigned ngrn; /* Next general-purpose register number. */ unsigned nsrn; /* Next vector register number. */ size_t nsaa; /* Next stack offset. */ #if defined (__APPLE__) unsigned allocating_variadic; #endif }; /* Initialize a procedure call argument marshalling state. */ static void arg_init (struct arg_state *state) { state->ngrn = 0; state->nsrn = 0; state->nsaa = 0; #if defined (__APPLE__) state->allocating_variadic = 0; #endif } /* Allocate an aligned slot on the stack and return a pointer to it. */ static void * allocate_to_stack (struct arg_state *state, void *stack, size_t alignment, size_t size) { size_t nsaa = state->nsaa; /* Round up the NSAA to the larger of 8 or the natural alignment of the argument's type. */ #if defined (__APPLE__) if (state->allocating_variadic && alignment < 8) alignment = 8; #else if (alignment < 8) alignment = 8; #endif nsaa = FFI_ALIGN (nsaa, alignment); state->nsaa = nsaa + size; return (char *)stack + nsaa; } static ffi_arg extend_integer_type (void *source, int type) { switch (type) { case FFI_TYPE_UINT8: return *(UINT8 *) source; case FFI_TYPE_SINT8: return *(SINT8 *) source; case FFI_TYPE_UINT16: return *(UINT16 *) source; case FFI_TYPE_SINT16: return *(SINT16 *) source; case FFI_TYPE_UINT32: return *(UINT32 *) source; case FFI_TYPE_INT: case FFI_TYPE_SINT32: return *(SINT32 *) source; case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: return *(UINT64 *) source; break; case FFI_TYPE_POINTER: return *(uintptr_t *) source; default: abort(); } } #if defined(_MSC_VER) void extend_hfa_type (void *dest, void *src, int h); #else static void extend_hfa_type (void *dest, void *src, int h) { ssize_t f = h - AARCH64_RET_S4; void *x0; asm volatile ( "adr %0, 0f\n" " add %0, %0, %1\n" " br %0\n" "0: ldp s16, s17, [%3]\n" /* S4 */ " ldp s18, s19, [%3, #8]\n" " b 4f\n" " ldp s16, s17, [%3]\n" /* S3 */ " ldr s18, [%3, #8]\n" " b 3f\n" " ldp s16, s17, [%3]\n" /* S2 */ " b 2f\n" " nop\n" " ldr s16, [%3]\n" /* S1 */ " b 1f\n" " nop\n" " ldp d16, d17, [%3]\n" /* D4 */ " ldp d18, d19, [%3, #16]\n" " b 4f\n" " ldp d16, d17, [%3]\n" /* D3 */ " ldr d18, [%3, #16]\n" " b 3f\n" " ldp d16, d17, [%3]\n" /* D2 */ " b 2f\n" " nop\n" " ldr d16, [%3]\n" /* D1 */ " b 1f\n" " nop\n" " ldp q16, q17, [%3]\n" /* Q4 */ " ldp q18, q19, [%3, #32]\n" " b 4f\n" " ldp q16, q17, [%3]\n" /* Q3 */ " ldr q18, [%3, #32]\n" " b 3f\n" " ldp q16, q17, [%3]\n" /* Q2 */ " b 2f\n" " nop\n" " ldr q16, [%3]\n" /* Q1 */ " b 1f\n" "4: str q19, [%2, #48]\n" "3: str q18, [%2, #32]\n" "2: str q17, [%2, #16]\n" "1: str q16, [%2]" : "=&r"(x0) : "r"(f * 12), "r"(dest), "r"(src) : "memory", "v16", "v17", "v18", "v19"); } #endif #if defined(_MSC_VER) void* compress_hfa_type (void *dest, void *src, int h); #else static void * compress_hfa_type (void *dest, void *reg, int h) { switch (h) { case AARCH64_RET_S1: if (dest == reg) { #ifdef __AARCH64EB__ dest += 12; #endif } else *(float *)dest = *(float *)reg; break; case AARCH64_RET_S2: asm ("ldp q16, q17, [%1]\n\t" "st2 { v16.s, v17.s }[0], [%0]" : : "r"(dest), "r"(reg) : "memory", "v16", "v17"); break; case AARCH64_RET_S3: asm ("ldp q16, q17, [%1]\n\t" "ldr q18, [%1, #32]\n\t" "st3 { v16.s, v17.s, v18.s }[0], [%0]" : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18"); break; case AARCH64_RET_S4: asm ("ldp q16, q17, [%1]\n\t" "ldp q18, q19, [%1, #32]\n\t" "st4 { v16.s, v17.s, v18.s, v19.s }[0], [%0]" : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19"); break; case AARCH64_RET_D1: if (dest == reg) { #ifdef __AARCH64EB__ dest += 8; #endif } else *(double *)dest = *(double *)reg; break; case AARCH64_RET_D2: asm ("ldp q16, q17, [%1]\n\t" "st2 { v16.d, v17.d }[0], [%0]" : : "r"(dest), "r"(reg) : "memory", "v16", "v17"); break; case AARCH64_RET_D3: asm ("ldp q16, q17, [%1]\n\t" "ldr q18, [%1, #32]\n\t" "st3 { v16.d, v17.d, v18.d }[0], [%0]" : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18"); break; case AARCH64_RET_D4: asm ("ldp q16, q17, [%1]\n\t" "ldp q18, q19, [%1, #32]\n\t" "st4 { v16.d, v17.d, v18.d, v19.d }[0], [%0]" : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19"); break; default: if (dest != reg) return memcpy (dest, reg, 16 * (4 - (h & 3))); break; } return dest; } #endif /* Either allocate an appropriate register for the argument type, or if none are available, allocate a stack slot and return a pointer to the allocated space. */ static void * allocate_int_to_reg_or_stack (struct call_context *context, struct arg_state *state, void *stack, size_t size) { if (state->ngrn < N_X_ARG_REG) return &context->x[state->ngrn++]; state->ngrn = N_X_ARG_REG; return allocate_to_stack (state, stack, size, size); } ffi_status FFI_HIDDEN ffi_prep_cif_machdep (ffi_cif *cif) { ffi_type *rtype = cif->rtype; size_t bytes = cif->bytes; int flags, i, n; switch (rtype->type) { case FFI_TYPE_VOID: flags = AARCH64_RET_VOID; break; case FFI_TYPE_UINT8: flags = AARCH64_RET_UINT8; break; case FFI_TYPE_UINT16: flags = AARCH64_RET_UINT16; break; case FFI_TYPE_UINT32: flags = AARCH64_RET_UINT32; break; case FFI_TYPE_SINT8: flags = AARCH64_RET_SINT8; break; case FFI_TYPE_SINT16: flags = AARCH64_RET_SINT16; break; case FFI_TYPE_INT: case FFI_TYPE_SINT32: flags = AARCH64_RET_SINT32; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: flags = AARCH64_RET_INT64; break; case FFI_TYPE_POINTER: flags = (sizeof(void *) == 4 ? AARCH64_RET_UINT32 : AARCH64_RET_INT64); break; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_STRUCT: case FFI_TYPE_COMPLEX: flags = is_vfp_type (rtype); if (flags == 0) { size_t s = rtype->size; if (s > 16) { flags = AARCH64_RET_VOID | AARCH64_RET_IN_MEM; bytes += 8; } else if (s == 16) flags = AARCH64_RET_INT128; else if (s == 8) flags = AARCH64_RET_INT64; else flags = AARCH64_RET_INT128 | AARCH64_RET_NEED_COPY; } break; default: abort(); } for (i = 0, n = cif->nargs; i < n; i++) if (is_vfp_type (cif->arg_types[i])) { flags |= AARCH64_FLAG_ARG_V; break; } /* Round the stack up to a multiple of the stack alignment requirement. */ cif->bytes = (unsigned) FFI_ALIGN(bytes, 16); cif->flags = flags; #if defined (__APPLE__) cif->aarch64_nfixedargs = 0; #endif return FFI_OK; } #if defined (__APPLE__) /* Perform Apple-specific cif processing for variadic calls */ ffi_status FFI_HIDDEN ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs) { ffi_status status = ffi_prep_cif_machdep (cif); cif->aarch64_nfixedargs = nfixedargs; return status; } #endif /* __APPLE__ */ extern void ffi_call_SYSV (struct call_context *context, void *frame, void (*fn)(void), void *rvalue, int flags, void *closure) FFI_HIDDEN; /* Call a function with the provided arguments and capture the return value. */ static void ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue, void **avalue, void *closure) { struct call_context *context; void *stack, *frame, *rvalue; struct arg_state state; size_t stack_bytes, rtype_size, rsize; int i, nargs, flags; ffi_type *rtype; flags = cif->flags; rtype = cif->rtype; rtype_size = rtype->size; stack_bytes = cif->bytes; /* If the target function returns a structure via hidden pointer, then we cannot allow a null rvalue. Otherwise, mash a null rvalue to void return type. */ rsize = 0; if (flags & AARCH64_RET_IN_MEM) { if (orig_rvalue == NULL) rsize = rtype_size; } else if (orig_rvalue == NULL) flags &= AARCH64_FLAG_ARG_V; else if (flags & AARCH64_RET_NEED_COPY) rsize = 16; /* Allocate consectutive stack for everything we'll need. */ context = alloca (sizeof(struct call_context) + stack_bytes + 32 + rsize); stack = context + 1; frame = (void*)((uintptr_t)stack + (uintptr_t)stack_bytes); rvalue = (rsize ? (void*)((uintptr_t)frame + 32) : orig_rvalue); arg_init (&state); for (i = 0, nargs = cif->nargs; i < nargs; i++) { ffi_type *ty = cif->arg_types[i]; size_t s = ty->size; void *a = avalue[i]; int h, t; t = ty->type; switch (t) { case FFI_TYPE_VOID: FFI_ASSERT (0); break; /* If the argument is a basic type the argument is allocated to an appropriate register, or if none are available, to the stack. */ case FFI_TYPE_INT: 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: do_pointer: { ffi_arg ext = extend_integer_type (a, t); if (state.ngrn < N_X_ARG_REG) context->x[state.ngrn++] = ext; else { void *d = allocate_to_stack (&state, stack, ty->alignment, s); state.ngrn = N_X_ARG_REG; /* Note that the default abi extends each argument to a full 64-bit slot, while the iOS abi allocates only enough space. */ #ifdef __APPLE__ memcpy(d, a, s); #else *(ffi_arg *)d = ext; #endif } } break; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_STRUCT: case FFI_TYPE_COMPLEX: { void *dest; h = is_vfp_type (ty); if (h) { int elems = 4 - (h & 3); #ifdef _M_ARM64 /* for handling armasm calling convention */ if (cif->is_variadic) { if (state.ngrn + elems <= N_X_ARG_REG) { dest = &context->x[state.ngrn]; state.ngrn += elems; extend_hfa_type(dest, a, h); break; } state.nsrn = N_X_ARG_REG; dest = allocate_to_stack(&state, stack, ty->alignment, s); } else { #endif /* for handling armasm calling convention */ if (state.nsrn + elems <= N_V_ARG_REG) { dest = &context->v[state.nsrn]; state.nsrn += elems; extend_hfa_type (dest, a, h); break; } state.nsrn = N_V_ARG_REG; dest = allocate_to_stack (&state, stack, ty->alignment, s); #ifdef _M_ARM64 /* for handling armasm calling convention */ } #endif /* for handling armasm calling convention */ } else if (s > 16) { /* If the argument is a composite type that is larger than 16 bytes, then the argument has been copied to memory, and the argument is replaced by a pointer to the copy. */ a = &avalue[i]; t = FFI_TYPE_POINTER; s = sizeof (void *); goto do_pointer; } else { size_t n = (s + 7) / 8; if (state.ngrn + n <= N_X_ARG_REG) { /* If the argument is a composite type and the size in double-words is not more than the number of available X registers, then the argument is copied into consecutive X registers. */ dest = &context->x[state.ngrn]; state.ngrn += (unsigned int)n; } else { /* Otherwise, there are insufficient X registers. Further X register allocations are prevented, the NSAA is adjusted and the argument is copied to memory at the adjusted NSAA. */ state.ngrn = N_X_ARG_REG; dest = allocate_to_stack (&state, stack, ty->alignment, s); } } memcpy (dest, a, s); } break; default: abort(); } #if defined (__APPLE__) if (i + 1 == cif->aarch64_nfixedargs) { state.ngrn = N_X_ARG_REG; state.nsrn = N_V_ARG_REG; state.allocating_variadic = 1; } #endif } ffi_call_SYSV (context, frame, fn, rvalue, flags, closure); if (flags & AARCH64_RET_NEED_COPY) memcpy (orig_rvalue, rvalue, rtype_size); } void ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) { ffi_call_int (cif, fn, rvalue, avalue, NULL); } #ifdef FFI_GO_CLOSURES void ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, void *closure) { ffi_call_int (cif, fn, rvalue, avalue, closure); } #endif /* FFI_GO_CLOSURES */ /* Build a trampoline. */ extern void ffi_closure_SYSV (void) FFI_HIDDEN; extern void ffi_closure_SYSV_V (void) FFI_HIDDEN; ffi_status ffi_prep_closure_loc (ffi_closure *closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc) { if (cif->abi != FFI_SYSV) return FFI_BAD_ABI; void (*start)(void); if (cif->flags & AARCH64_FLAG_ARG_V) start = ffi_closure_SYSV_V; else start = ffi_closure_SYSV; #if FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE); config[0] = closure; config[1] = start; #endif #else static const unsigned char trampoline[16] = { 0x90, 0x00, 0x00, 0x58, /* ldr x16, tramp+16 */ 0xf1, 0xff, 0xff, 0x10, /* adr x17, tramp+0 */ 0x00, 0x02, 0x1f, 0xd6 /* br x16 */ }; char *tramp = closure->tramp; memcpy (tramp, trampoline, sizeof(trampoline)); *(UINT64 *)(tramp + 16) = (uintptr_t)start; ffi_clear_cache(tramp, tramp + FFI_TRAMPOLINE_SIZE); /* Also flush the cache for code mapping. */ #ifdef _M_ARM64 // Not using dlmalloc.c for Windows ARM64 builds // so calling ffi_data_to_code_pointer() isn't necessary unsigned char *tramp_code = tramp; #else unsigned char *tramp_code = ffi_data_to_code_pointer (tramp); #endif ffi_clear_cache (tramp_code, tramp_code + FFI_TRAMPOLINE_SIZE); #endif closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK; } #ifdef FFI_GO_CLOSURES extern void ffi_go_closure_SYSV (void) FFI_HIDDEN; extern void ffi_go_closure_SYSV_V (void) FFI_HIDDEN; ffi_status ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*)) { void (*start)(void); if (cif->abi != FFI_SYSV) return FFI_BAD_ABI; if (cif->flags & AARCH64_FLAG_ARG_V) start = ffi_go_closure_SYSV_V; else start = ffi_go_closure_SYSV; closure->tramp = start; closure->cif = cif; closure->fun = fun; return FFI_OK; } #endif /* FFI_GO_CLOSURES */ /* Primary handler to setup and invoke a function within a closure. A closure when invoked enters via the assembler wrapper ffi_closure_SYSV(). The wrapper allocates a call context on the stack, saves the interesting registers (from the perspective of the calling convention) into the context then passes control to ffi_closure_SYSV_inner() passing the saved context and a pointer to the stack at the point ffi_closure_SYSV() was invoked. On the return path the assembler wrapper will reload call context registers. ffi_closure_SYSV_inner() marshalls the call context into ffi value descriptors, invokes the wrapped function, then marshalls the return value back into the call context. */ int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, struct call_context *context, void *stack, void *rvalue, void *struct_rvalue) { void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); int i, h, nargs, flags; struct arg_state state; arg_init (&state); for (i = 0, nargs = cif->nargs; i < nargs; i++) { ffi_type *ty = cif->arg_types[i]; int t = ty->type; size_t n, s = ty->size; switch (t) { case FFI_TYPE_VOID: FFI_ASSERT (0); break; case FFI_TYPE_INT: 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: avalue[i] = allocate_int_to_reg_or_stack (context, &state, stack, s); break; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_STRUCT: case FFI_TYPE_COMPLEX: h = is_vfp_type (ty); if (h) { n = 4 - (h & 3); #ifdef _M_ARM64 /* for handling armasm calling convention */ if (cif->is_variadic) { if (state.ngrn + n <= N_X_ARG_REG) { void *reg = &context->x[state.ngrn]; state.ngrn += (unsigned int)n; /* Eeek! We need a pointer to the structure, however the homogeneous float elements are being passed in individual registers, therefore for float and double the structure is not represented as a contiguous sequence of bytes in our saved register context. We don't need the original contents of the register storage, so we reformat the structure into the same memory. */ avalue[i] = compress_hfa_type(reg, reg, h); } else { state.ngrn = N_X_ARG_REG; state.nsrn = N_V_ARG_REG; avalue[i] = allocate_to_stack(&state, stack, ty->alignment, s); } } else { #endif /* for handling armasm calling convention */ if (state.nsrn + n <= N_V_ARG_REG) { void *reg = &context->v[state.nsrn]; state.nsrn += (unsigned int)n; avalue[i] = compress_hfa_type(reg, reg, h); } else { state.nsrn = N_V_ARG_REG; avalue[i] = allocate_to_stack(&state, stack, ty->alignment, s); } #ifdef _M_ARM64 /* for handling armasm calling convention */ } #endif /* for handling armasm calling convention */ } else if (s > 16) { /* Replace Composite type of size greater than 16 with a pointer. */ avalue[i] = *(void **) allocate_int_to_reg_or_stack (context, &state, stack, sizeof (void *)); } else { n = (s + 7) / 8; if (state.ngrn + n <= N_X_ARG_REG) { avalue[i] = &context->x[state.ngrn]; state.ngrn += (unsigned int)n; } else { state.ngrn = N_X_ARG_REG; avalue[i] = allocate_to_stack(&state, stack, ty->alignment, s); } } break; default: abort(); } #if defined (__APPLE__) if (i + 1 == cif->aarch64_nfixedargs) { state.ngrn = N_X_ARG_REG; state.nsrn = N_V_ARG_REG; state.allocating_variadic = 1; } #endif } flags = cif->flags; if (flags & AARCH64_RET_IN_MEM) rvalue = struct_rvalue; fun (cif, rvalue, avalue, user_data); return flags; } #endif /* (__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)*/ ====================File: src/aarch64/ffitarget.h==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #elif defined(_M_ARM64) #define FFI_SIZEOF_ARG 8 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #ifdef _M_ARM64 #define FFI_EXTRA_CIF_FIELDS unsigned is_variadic #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #elif !defined(_M_ARM64) /* iOS and Windows reserve x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #ifndef _M_ARM64 /* No complex type on Windows */ #define FFI_TARGET_HAS_COMPLEX_TYPE #endif #endif ====================File: src/aarch64/sysv.S==================== /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if defined(__aarch64__) || defined(__arm64__) #define LIBFFI_ASM #include #include #include #include "internal.h" #ifdef HAVE_MACHINE_ASM_H #include #else #ifdef __USER_LABEL_PREFIX__ #define CONCAT1(a, b) CONCAT2(a, b) #define CONCAT2(a, b) a ## b /* Use the right prefix for global labels. */ #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) #else #define CNAME(x) x #endif #endif #ifdef __AARCH64EB__ # define BE(X) X #else # define BE(X) 0 #endif #ifdef __ILP32__ #define PTR_REG(n) w##n #else #define PTR_REG(n) x##n #endif #ifdef __ILP32__ #define PTR_SIZE 4 #else #define PTR_SIZE 8 #endif .text .align 4 /* ffi_call_SYSV extern void ffi_call_SYSV (void *stack, void *frame, void (*fn)(void), void *rvalue, int flags, void *closure); Therefore on entry we have: x0 stack x1 frame x2 fn x3 rvalue x4 flags x5 closure */ cfi_startproc CNAME(ffi_call_SYSV): /* Use a stack frame allocated by our caller. */ cfi_def_cfa(x1, 32); stp x29, x30, [x1] mov x29, x1 mov sp, x0 cfi_def_cfa_register(x29) cfi_rel_offset (x29, 0) cfi_rel_offset (x30, 8) mov x9, x2 /* save fn */ mov x8, x3 /* install structure return */ #ifdef FFI_GO_CLOSURES mov x18, x5 /* install static chain */ #endif stp x3, x4, [x29, #16] /* save rvalue and flags */ /* Load the vector argument passing registers, if necessary. */ tbz w4, #AARCH64_FLAG_ARG_V_BIT, 1f ldp q0, q1, [sp, #0] ldp q2, q3, [sp, #32] ldp q4, q5, [sp, #64] ldp q6, q7, [sp, #96] 1: /* Load the core argument passing registers, including the structure return pointer. */ ldp x0, x1, [sp, #16*N_V_ARG_REG + 0] ldp x2, x3, [sp, #16*N_V_ARG_REG + 16] ldp x4, x5, [sp, #16*N_V_ARG_REG + 32] ldp x6, x7, [sp, #16*N_V_ARG_REG + 48] /* Deallocate the context, leaving the stacked arguments. */ add sp, sp, #CALL_CONTEXT_SIZE blr x9 /* call fn */ ldp x3, x4, [x29, #16] /* reload rvalue and flags */ /* Partially deconstruct the stack frame. */ mov sp, x29 cfi_def_cfa_register (sp) ldp x29, x30, [x29] /* Save the return value as directed. */ adr x5, 0f and w4, w4, #AARCH64_RET_MASK add x5, x5, x4, lsl #3 br x5 /* Note that each table entry is 2 insns, and thus 8 bytes. For integer data, note that we're storing into ffi_arg and therefore we want to extend to 64 bits; these types have two consecutive entries allocated for them. */ .align 4 0: ret /* VOID */ nop 1: str x0, [x3] /* INT64 */ ret 2: stp x0, x1, [x3] /* INT128 */ ret 3: brk #1000 /* UNUSED */ ret 4: brk #1000 /* UNUSED */ ret 5: brk #1000 /* UNUSED */ ret 6: brk #1000 /* UNUSED */ ret 7: brk #1000 /* UNUSED */ ret 8: st4 { v0.s, v1.s, v2.s, v3.s }[0], [x3] /* S4 */ ret 9: st3 { v0.s, v1.s, v2.s }[0], [x3] /* S3 */ ret 10: stp s0, s1, [x3] /* S2 */ ret 11: str s0, [x3] /* S1 */ ret 12: st4 { v0.d, v1.d, v2.d, v3.d }[0], [x3] /* D4 */ ret 13: st3 { v0.d, v1.d, v2.d }[0], [x3] /* D3 */ ret 14: stp d0, d1, [x3] /* D2 */ ret 15: str d0, [x3] /* D1 */ ret 16: str q3, [x3, #48] /* Q4 */ nop 17: str q2, [x3, #32] /* Q3 */ nop 18: stp q0, q1, [x3] /* Q2 */ ret 19: str q0, [x3] /* Q1 */ ret 20: uxtb w0, w0 /* UINT8 */ str x0, [x3] 21: ret /* reserved */ nop 22: uxth w0, w0 /* UINT16 */ str x0, [x3] 23: ret /* reserved */ nop 24: mov w0, w0 /* UINT32 */ str x0, [x3] 25: ret /* reserved */ nop 26: sxtb x0, w0 /* SINT8 */ str x0, [x3] 27: ret /* reserved */ nop 28: sxth x0, w0 /* SINT16 */ str x0, [x3] 29: ret /* reserved */ nop 30: sxtw x0, w0 /* SINT32 */ str x0, [x3] 31: ret /* reserved */ nop cfi_endproc .globl CNAME(ffi_call_SYSV) FFI_HIDDEN(CNAME(ffi_call_SYSV)) #ifdef __ELF__ .type CNAME(ffi_call_SYSV), #function .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV) #endif /* ffi_closure_SYSV Closure invocation glue. This is the low level code invoked directly by the closure trampoline to setup and call a closure. On entry x17 points to a struct ffi_closure, x16 has been clobbered all other registers are preserved. We allocate a call context and save the argument passing registers, then invoked the generic C ffi_closure_SYSV_inner() function to do all the real work, on return we load the result passing registers back from the call context. */ #define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64) .align 4 CNAME(ffi_closure_SYSV_V): cfi_startproc stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) cfi_rel_offset (x29, 0) cfi_rel_offset (x30, 8) /* Save the argument passing vector registers. */ stp q0, q1, [sp, #16 + 0] stp q2, q3, [sp, #16 + 32] stp q4, q5, [sp, #16 + 64] stp q6, q7, [sp, #16 + 96] b 0f cfi_endproc .globl CNAME(ffi_closure_SYSV_V) FFI_HIDDEN(CNAME(ffi_closure_SYSV_V)) #ifdef __ELF__ .type CNAME(ffi_closure_SYSV_V), #function .size CNAME(ffi_closure_SYSV_V), . - CNAME(ffi_closure_SYSV_V) #endif .align 4 cfi_startproc CNAME(ffi_closure_SYSV): stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) cfi_rel_offset (x29, 0) cfi_rel_offset (x30, 8) 0: mov x29, sp /* Save the argument passing core registers. */ stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0] stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16] stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32] stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48] /* Load ffi_closure_inner arguments. */ ldp PTR_REG(0), PTR_REG(1), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET] /* load cif, fn */ ldr PTR_REG(2), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET+PTR_SIZE*2] /* load user_data */ .Ldo_closure: add x3, sp, #16 /* load context */ add x4, sp, #ffi_closure_SYSV_FS /* load stack */ add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */ mov x6, x8 /* load struct_rval */ bl CNAME(ffi_closure_SYSV_inner) /* Load the return value as directed. */ adr x1, 0f and w0, w0, #AARCH64_RET_MASK add x1, x1, x0, lsl #3 add x3, sp, #16+CALL_CONTEXT_SIZE br x1 /* Note that each table entry is 2 insns, and thus 8 bytes. */ .align 4 0: b 99f /* VOID */ nop 1: ldr x0, [x3] /* INT64 */ b 99f 2: ldp x0, x1, [x3] /* INT128 */ b 99f 3: brk #1000 /* UNUSED */ nop 4: brk #1000 /* UNUSED */ nop 5: brk #1000 /* UNUSED */ nop 6: brk #1000 /* UNUSED */ nop 7: brk #1000 /* UNUSED */ nop 8: ldr s3, [x3, #12] /* S4 */ nop 9: ldr s2, [x3, #8] /* S3 */ nop 10: ldp s0, s1, [x3] /* S2 */ b 99f 11: ldr s0, [x3] /* S1 */ b 99f 12: ldr d3, [x3, #24] /* D4 */ nop 13: ldr d2, [x3, #16] /* D3 */ nop 14: ldp d0, d1, [x3] /* D2 */ b 99f 15: ldr d0, [x3] /* D1 */ b 99f 16: ldr q3, [x3, #48] /* Q4 */ nop 17: ldr q2, [x3, #32] /* Q3 */ nop 18: ldp q0, q1, [x3] /* Q2 */ b 99f 19: ldr q0, [x3] /* Q1 */ b 99f 20: ldrb w0, [x3, #BE(7)] /* UINT8 */ b 99f 21: brk #1000 /* reserved */ nop 22: ldrh w0, [x3, #BE(6)] /* UINT16 */ b 99f 23: brk #1000 /* reserved */ nop 24: ldr w0, [x3, #BE(4)] /* UINT32 */ b 99f 25: brk #1000 /* reserved */ nop 26: ldrsb x0, [x3, #BE(7)] /* SINT8 */ b 99f 27: brk #1000 /* reserved */ nop 28: ldrsh x0, [x3, #BE(6)] /* SINT16 */ b 99f 29: brk #1000 /* reserved */ nop 30: ldrsw x0, [x3, #BE(4)] /* SINT32 */ nop 31: /* reserved */ 99: ldp x29, x30, [sp], #ffi_closure_SYSV_FS cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS) cfi_restore (x29) cfi_restore (x30) ret cfi_endproc .globl CNAME(ffi_closure_SYSV) FFI_HIDDEN(CNAME(ffi_closure_SYSV)) #ifdef __ELF__ .type CNAME(ffi_closure_SYSV), #function .size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV) #endif #if FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #include .align PAGE_MAX_SHIFT CNAME(ffi_closure_trampoline_table_page): .rept PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE adr x16, -PAGE_MAX_SIZE ldp x17, x16, [x16] br x16 nop /* each entry in the trampoline config page is 2*sizeof(void*) so the trampoline itself cannot be smaller that 16 bytes */ .endr .globl CNAME(ffi_closure_trampoline_table_page) FFI_HIDDEN(CNAME(ffi_closure_trampoline_table_page)) #ifdef __ELF__ .type CNAME(ffi_closure_trampoline_table_page), #function .size CNAME(ffi_closure_trampoline_table_page), . - CNAME(ffi_closure_trampoline_table_page) #endif #endif #endif /* FFI_EXEC_TRAMPOLINE_TABLE */ #ifdef FFI_GO_CLOSURES .align 4 CNAME(ffi_go_closure_SYSV_V): cfi_startproc stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) cfi_rel_offset (x29, 0) cfi_rel_offset (x30, 8) /* Save the argument passing vector registers. */ stp q0, q1, [sp, #16 + 0] stp q2, q3, [sp, #16 + 32] stp q4, q5, [sp, #16 + 64] stp q6, q7, [sp, #16 + 96] b 0f cfi_endproc .globl CNAME(ffi_go_closure_SYSV_V) FFI_HIDDEN(CNAME(ffi_go_closure_SYSV_V)) #ifdef __ELF__ .type CNAME(ffi_go_closure_SYSV_V), #function .size CNAME(ffi_go_closure_SYSV_V), . - CNAME(ffi_go_closure_SYSV_V) #endif .align 4 cfi_startproc CNAME(ffi_go_closure_SYSV): stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) cfi_rel_offset (x29, 0) cfi_rel_offset (x30, 8) 0: mov x29, sp /* Save the argument passing core registers. */ stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0] stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16] stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32] stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48] /* Load ffi_closure_inner arguments. */ ldp PTR_REG(0), PTR_REG(1), [x18, #PTR_SIZE]/* load cif, fn */ mov x2, x18 /* load user_data */ b .Ldo_closure cfi_endproc .globl CNAME(ffi_go_closure_SYSV) FFI_HIDDEN(CNAME(ffi_go_closure_SYSV)) #ifdef __ELF__ .type CNAME(ffi_go_closure_SYSV), #function .size CNAME(ffi_go_closure_SYSV), . - CNAME(ffi_go_closure_SYSV) #endif #endif /* FFI_GO_CLOSURES */ #endif /* __arm64__ */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",%progbits #endif ====================File: src/arm/ffi.c==================== /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2011 Timothy Wall Copyright (c) 2011 Plausible Labs Cooperative, Inc. Copyright (c) 2011 Anthony Green Copyright (c) 2011 Free Software Foundation Copyright (c) 1998, 2008, 2011 Red Hat, Inc. ARM Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #if defined(__arm__) || defined(_M_ARM) #include #include #include #include #include #include "internal.h" #if defined(_MSC_VER) && defined(_M_ARM) #define WIN32_LEAN_AND_MEAN #include #endif #if FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #include #endif #else #ifndef _M_ARM extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN; #else extern unsigned int ffi_arm_trampoline[3] FFI_HIDDEN; #endif #endif /* Forward declares. */ static int vfp_type_p (const ffi_type *); static void layout_vfp_args (ffi_cif *); static void * ffi_align (ffi_type *ty, void *p) { /* Align if necessary */ size_t alignment; #ifdef _WIN32_WCE alignment = 4; #else alignment = ty->alignment; if (alignment < 4) alignment = 4; #endif return (void *) FFI_ALIGN (p, alignment); } static size_t ffi_put_arg (ffi_type *ty, void *src, void *dst) { size_t z = ty->size; switch (ty->type) { case FFI_TYPE_SINT8: *(UINT32 *)dst = *(SINT8 *)src; break; case FFI_TYPE_UINT8: *(UINT32 *)dst = *(UINT8 *)src; break; case FFI_TYPE_SINT16: *(UINT32 *)dst = *(SINT16 *)src; break; case FFI_TYPE_UINT16: *(UINT32 *)dst = *(UINT16 *)src; break; case FFI_TYPE_INT: case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_POINTER: #ifndef _MSC_VER case FFI_TYPE_FLOAT: #endif *(UINT32 *)dst = *(UINT32 *)src; break; #ifdef _MSC_VER // casting a float* to a UINT32* doesn't work on Windows case FFI_TYPE_FLOAT: *(uintptr_t *)dst = 0; *(float *)dst = *(float *)src; break; #endif case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_DOUBLE: *(UINT64 *)dst = *(UINT64 *)src; break; case FFI_TYPE_STRUCT: case FFI_TYPE_COMPLEX: memcpy (dst, src, z); break; default: abort(); } return FFI_ALIGN (z, 4); } /* ffi_prep_args is called once stack space has been allocated for the function's arguments. The vfp_space parameter is the load area for VFP regs, the return value is cif->vfp_used (word bitset of VFP regs used for passing arguments). These are only used for the VFP hard-float ABI. */ static void ffi_prep_args_SYSV (ffi_cif *cif, int flags, void *rvalue, void **avalue, char *argp) { ffi_type **arg_types = cif->arg_types; int i, n; if (flags == ARM_TYPE_STRUCT) { *(void **) argp = rvalue; argp += 4; } for (i = 0, n = cif->nargs; i < n; i++) { ffi_type *ty = arg_types[i]; argp = ffi_align (ty, argp); argp += ffi_put_arg (ty, avalue[i], argp); } } static void ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue, void **avalue, char *stack, char *vfp_space) { ffi_type **arg_types = cif->arg_types; int i, n, vi = 0; char *argp, *regp, *eo_regp; char stack_used = 0; char done_with_regs = 0; /* The first 4 words on the stack are used for values passed in core registers. */ regp = stack; eo_regp = argp = regp + 16; /* If the function returns an FFI_TYPE_STRUCT in memory, that address is passed in r0 to the function. */ if (flags == ARM_TYPE_STRUCT) { *(void **) regp = rvalue; regp += 4; } for (i = 0, n = cif->nargs; i < n; i++) { ffi_type *ty = arg_types[i]; void *a = avalue[i]; int is_vfp_type = vfp_type_p (ty); /* Allocated in VFP registers. */ if (vi < cif->vfp_nargs && is_vfp_type) { char *vfp_slot = vfp_space + cif->vfp_args[vi++] * 4; ffi_put_arg (ty, a, vfp_slot); continue; } /* Try allocating in core registers. */ else if (!done_with_regs && !is_vfp_type) { char *tregp = ffi_align (ty, regp); size_t size = ty->size; size = (size < 4) ? 4 : size; // pad /* Check if there is space left in the aligned register area to place the argument. */ if (tregp + size <= eo_regp) { regp = tregp + ffi_put_arg (ty, a, tregp); done_with_regs = (regp == argp); // ensure we did not write into the stack area FFI_ASSERT (regp <= argp); continue; } /* In case there are no arguments in the stack area yet, the argument is passed in the remaining core registers and on the stack. */ else if (!stack_used) { stack_used = 1; done_with_regs = 1; argp = tregp + ffi_put_arg (ty, a, tregp); FFI_ASSERT (eo_regp < argp); continue; } } /* Base case, arguments are passed on the stack */ stack_used = 1; argp = ffi_align (ty, argp); argp += ffi_put_arg (ty, a, argp); } } /* Perform machine dependent cif processing */ ffi_status FFI_HIDDEN ffi_prep_cif_machdep (ffi_cif *cif) { int flags = 0, cabi = cif->abi; size_t bytes = cif->bytes; /* Map out the register placements of VFP register args. The VFP hard-float calling conventions are slightly more sophisticated than the base calling conventions, so we do it here instead of in ffi_prep_args(). */ if (cabi == FFI_VFP) layout_vfp_args (cif); /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: flags = ARM_TYPE_VOID; break; case FFI_TYPE_INT: 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_POINTER: flags = ARM_TYPE_INT; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: flags = ARM_TYPE_INT64; break; case FFI_TYPE_FLOAT: flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_S : ARM_TYPE_INT); break; case FFI_TYPE_DOUBLE: flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_D : ARM_TYPE_INT64); break; case FFI_TYPE_STRUCT: case FFI_TYPE_COMPLEX: if (cabi == FFI_VFP) { int h = vfp_type_p (cif->rtype); flags = ARM_TYPE_VFP_N; if (h == 0x100 + FFI_TYPE_FLOAT) flags = ARM_TYPE_VFP_S; if (h == 0x100 + FFI_TYPE_DOUBLE) flags = ARM_TYPE_VFP_D; if (h != 0) break; } /* A Composite Type not larger than 4 bytes is returned in r0. A Composite Type larger than 4 bytes, or whose size cannot be determined statically ... is stored in memory at an address passed [in r0]. */ if (cif->rtype->size <= 4) flags = ARM_TYPE_INT; else { flags = ARM_TYPE_STRUCT; bytes += 4; } break; default: abort(); } /* Round the stack up to a multiple of 8 bytes. This isn't needed everywhere, but it is on some platforms, and it doesn't harm anything when it isn't needed. */ bytes = FFI_ALIGN (bytes, 8); /* Minimum stack space is the 4 register arguments that we pop. */ if (bytes < 4*4) bytes = 4*4; cif->bytes = bytes; cif->flags = flags; return FFI_OK; } /* Perform machine dependent cif processing for variadic calls */ ffi_status FFI_HIDDEN ffi_prep_cif_machdep_var (ffi_cif * cif, unsigned int nfixedargs, unsigned int ntotalargs) { /* VFP variadic calls actually use the SYSV ABI */ if (cif->abi == FFI_VFP) cif->abi = FFI_SYSV; return ffi_prep_cif_machdep (cif); } /* Prototypes for assembly functions, in sysv.S. */ struct call_frame { void *fp; void *lr; void *rvalue; int flags; void *closure; }; extern void ffi_call_SYSV (void *stack, struct call_frame *, void (*fn) (void)) FFI_HIDDEN; extern void ffi_call_VFP (void *vfp_space, struct call_frame *, void (*fn) (void), unsigned vfp_used) FFI_HIDDEN; static void ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue, void *closure) { int flags = cif->flags; ffi_type *rtype = cif->rtype; size_t bytes, rsize, vfp_size; char *stack, *vfp_space, *new_rvalue; struct call_frame *frame; rsize = 0; if (rvalue == NULL) { /* If the return value is a struct and we don't have a return value address then we need to make one. Otherwise the return value is in registers and we can ignore them. */ if (flags == ARM_TYPE_STRUCT) rsize = rtype->size; else flags = ARM_TYPE_VOID; } else if (flags == ARM_TYPE_VFP_N) { /* Largest case is double x 4. */ rsize = 32; } else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT) rsize = 4; /* Largest case. */ vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0); bytes = cif->bytes; stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize); vfp_space = NULL; if (vfp_size) { vfp_space = stack; stack += vfp_size; } frame = (struct call_frame *)(stack + bytes); new_rvalue = rvalue; if (rsize) new_rvalue = (void *)(frame + 1); frame->rvalue = new_rvalue; frame->flags = flags; frame->closure = closure; if (vfp_space) { ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space); ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used); } else { ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack); ffi_call_SYSV (stack, frame, fn); } if (rvalue && rvalue != new_rvalue) memcpy (rvalue, new_rvalue, rtype->size); } void ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) { ffi_call_int (cif, fn, rvalue, avalue, NULL); } void ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, void *closure) { ffi_call_int (cif, fn, rvalue, avalue, closure); } static void * ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue, char *argp, void **avalue) { ffi_type **arg_types = cif->arg_types; int i, n; if (cif->flags == ARM_TYPE_STRUCT) { rvalue = *(void **) argp; argp += 4; } else { if (cif->rtype->size && cif->rtype->size < 4) *(uint32_t *) rvalue = 0; } for (i = 0, n = cif->nargs; i < n; i++) { ffi_type *ty = arg_types[i]; size_t z = ty->size; argp = ffi_align (ty, argp); avalue[i] = (void *) argp; argp += z; } return rvalue; } static void * ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack, char *vfp_space, void **avalue) { ffi_type **arg_types = cif->arg_types; int i, n, vi = 0; char *argp, *regp, *eo_regp; char done_with_regs = 0; char stack_used = 0; regp = stack; eo_regp = argp = regp + 16; if (cif->flags == ARM_TYPE_STRUCT) { rvalue = *(void **) regp; regp += 4; } for (i = 0, n = cif->nargs; i < n; i++) { ffi_type *ty = arg_types[i]; int is_vfp_type = vfp_type_p (ty); size_t z = ty->size; if (vi < cif->vfp_nargs && is_vfp_type) { avalue[i] = vfp_space + cif->vfp_args[vi++] * 4; continue; } else if (!done_with_regs && !is_vfp_type) { char *tregp = ffi_align (ty, regp); z = (z < 4) ? 4 : z; // pad /* If the arguments either fits into the registers or uses registers and stack, while we haven't read other things from the stack */ if (tregp + z <= eo_regp || !stack_used) { /* Because we're little endian, this is what it turns into. */ avalue[i] = (void *) tregp; regp = tregp + z; /* If we read past the last core register, make sure we have not read from the stack before and continue reading after regp. */ if (regp > eo_regp) { FFI_ASSERT (!stack_used); argp = regp; } if (regp >= eo_regp) { done_with_regs = 1; stack_used = 1; } continue; } } stack_used = 1; argp = ffi_align (ty, argp); avalue[i] = (void *) argp; argp += z; } return rvalue; } struct closure_frame { char vfp_space[8*8] __attribute__((aligned(8))); char result[8*4]; char argp[]; }; int FFI_HIDDEN ffi_closure_inner_SYSV (ffi_cif *cif, void (*fun) (ffi_cif *, void *, void **, void *), void *user_data, struct closure_frame *frame) { void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result, frame->argp, avalue); fun (cif, rvalue, avalue, user_data); return cif->flags; } int FFI_HIDDEN ffi_closure_inner_VFP (ffi_cif *cif, void (*fun) (ffi_cif *, void *, void **, void *), void *user_data, struct closure_frame *frame) { void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp, frame->vfp_space, avalue); fun (cif, rvalue, avalue, user_data); return cif->flags; } void ffi_closure_SYSV (void) FFI_HIDDEN; void ffi_closure_VFP (void) FFI_HIDDEN; void ffi_go_closure_SYSV (void) FFI_HIDDEN; void ffi_go_closure_VFP (void) FFI_HIDDEN; /* the cif must already be prep'ed */ ffi_status ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif, void (*fun) (ffi_cif *, void *, void **, void *), void *user_data, void *codeloc) { void (*closure_func) (void) = ffi_closure_SYSV; if (cif->abi == FFI_VFP) { /* We only need take the vfp path if there are vfp arguments. */ if (cif->vfp_used) closure_func = ffi_closure_VFP; } else if (cif->abi != FFI_SYSV) return FFI_BAD_ABI; #if FFI_EXEC_TRAMPOLINE_TABLE void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE); config[0] = closure; config[1] = closure_func; #else #ifndef _M_ARM memcpy(closure->tramp, ffi_arm_trampoline, 8); #else // cast away function type so MSVC doesn't set the lower bit of the function pointer memcpy(closure->tramp, (void*)((uintptr_t)ffi_arm_trampoline & 0xFFFFFFFE), FFI_TRAMPOLINE_CLOSURE_OFFSET); #endif #if defined (__QNX__) msync(closure->tramp, 8, 0x1000000); /* clear data map */ msync(codeloc, 8, 0x1000000); /* clear insn map */ #elif defined(_MSC_VER) FlushInstructionCache(GetCurrentProcess(), closure->tramp, FFI_TRAMPOLINE_SIZE); #else __clear_cache(closure->tramp, closure->tramp + 8); /* clear data map */ __clear_cache(codeloc, codeloc + 8); /* clear insn map */ #endif #ifdef _M_ARM *(void(**)(void))(closure->tramp + FFI_TRAMPOLINE_CLOSURE_FUNCTION) = closure_func; #else *(void (**)(void))(closure->tramp + 8) = closure_func; #endif #endif closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK; } ffi_status ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, void (*fun) (ffi_cif *, void *, void **, void *)) { void (*closure_func) (void) = ffi_go_closure_SYSV; if (cif->abi == FFI_VFP) { /* We only need take the vfp path if there are vfp arguments. */ if (cif->vfp_used) closure_func = ffi_go_closure_VFP; } else if (cif->abi != FFI_SYSV) return FFI_BAD_ABI; closure->tramp = closure_func; closure->cif = cif; closure->fun = fun; return FFI_OK; } /* Below are routines for VFP hard-float support. */ /* A subroutine of vfp_type_p. Given a structure type, return the type code of the first non-structure element. Recurse for structure elements. Return -1 if the structure is in fact empty, i.e. no nested elements. */ static int is_hfa0 (const ffi_type *ty) { ffi_type **elements = ty->elements; int i, ret = -1; if (elements != NULL) for (i = 0; elements[i]; ++i) { ret = elements[i]->type; if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX) { ret = is_hfa0 (elements[i]); if (ret < 0) continue; } break; } return ret; } /* A subroutine of vfp_type_p. Given a structure type, return true if all of the non-structure elements are the same as CANDIDATE. */ static int is_hfa1 (const ffi_type *ty, int candidate) { ffi_type **elements = ty->elements; int i; if (elements != NULL) for (i = 0; elements[i]; ++i) { int t = elements[i]->type; if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) { if (!is_hfa1 (elements[i], candidate)) return 0; } else if (t != candidate) return 0; } return 1; } /* Determine if TY is an homogenous floating point aggregate (HFA). That is, a structure consisting of 1 to 4 members of all the same type, where that type is a floating point scalar. Returns non-zero iff TY is an HFA. The result is an encoded value where bits 0-7 contain the type code, and bits 8-10 contain the element count. */ static int vfp_type_p (const ffi_type *ty) { ffi_type **elements; int candidate, i; size_t size, ele_count; /* Quickest tests first. */ candidate = ty->type; switch (ty->type) { default: return 0; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: ele_count = 1; goto done; case FFI_TYPE_COMPLEX: candidate = ty->elements[0]->type; if (candidate != FFI_TYPE_FLOAT && candidate != FFI_TYPE_DOUBLE) return 0; ele_count = 2; goto done; case FFI_TYPE_STRUCT: break; } /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */ size = ty->size; if (size < 4 || size > 32) return 0; /* Find the type of the first non-structure member. */ elements = ty->elements; candidate = elements[0]->type; if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX) { for (i = 0; ; ++i) { candidate = is_hfa0 (elements[i]); if (candidate >= 0) break; } } /* If the first member is not a floating point type, it's not an HFA. Also quickly re-check the size of the structure. */ switch (candidate) { case FFI_TYPE_FLOAT: ele_count = size / sizeof(float); if (size != ele_count * sizeof(float)) return 0; break; case FFI_TYPE_DOUBLE: ele_count = size / sizeof(double); if (size != ele_count * sizeof(double)) return 0; break; default: return 0; } if (ele_count > 4) return 0; /* Finally, make sure that all scalar elements are the same type. */ for (i = 0; elements[i]; ++i) { int t = elements[i]->type; if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) { if (!is_hfa1 (elements[i], candidate)) return 0; } else if (t != candidate) return 0; } /* All tests succeeded. Encode the result. */ done: return (ele_count << 8) | candidate; } static int place_vfp_arg (ffi_cif *cif, int h) { unsigned short reg = cif->vfp_reg_free; int align = 1, nregs = h >> 8; if ((h & 0xff) == FFI_TYPE_DOUBLE) align = 2, nregs *= 2; /* Align register number. */ if ((reg & 1) && align == 2) reg++; while (reg + nregs <= 16) { int s, new_used = 0; for (s = reg; s < reg + nregs; s++) { new_used |= (1 << s); if (cif->vfp_used & (1 << s)) { reg += align; goto next_reg; } } /* Found regs to allocate. */ cif->vfp_used |= new_used; cif->vfp_args[cif->vfp_nargs++] = (signed char)reg; /* Update vfp_reg_free. */ if (cif->vfp_used & (1 << cif->vfp_reg_free)) { reg += nregs; while (cif->vfp_used & (1 << reg)) reg += 1; cif->vfp_reg_free = reg; } return 0; next_reg:; } // done, mark all regs as used cif->vfp_reg_free = 16; cif->vfp_used = 0xFFFF; return 1; } static void layout_vfp_args (ffi_cif * cif) { unsigned int i; /* Init VFP fields */ cif->vfp_used = 0; cif->vfp_nargs = 0; cif->vfp_reg_free = 0; memset (cif->vfp_args, -1, 16); /* Init to -1. */ for (i = 0; i < cif->nargs; i++) { int h = vfp_type_p (cif->arg_types[i]); if (h && place_vfp_arg (cif, h) == 1) break; } } #endif /* __arm__ or _M_ARM */ ====================File: src/arm/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (c) 2010 CodeSourcery Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_VFP, FFI_LAST_ABI, #if defined(__ARM_PCS_VFP) || defined(_M_ARM) FFI_DEFAULT_ABI = FFI_VFP, #else FFI_DEFAULT_ABI = FFI_SYSV, #endif } ffi_abi; #endif #define FFI_EXTRA_CIF_FIELDS \ int vfp_used; \ unsigned short vfp_reg_free, vfp_nargs; \ signed char vfp_args[16] \ #define FFI_TARGET_SPECIFIC_VARIADIC #ifndef _M_ARM #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 #else #error "No trampoline table implementation" #endif #else #ifdef _MSC_VER #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_FUNCTION 12 #else #define FFI_TRAMPOLINE_SIZE 12 #endif #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #endif ====================File: src/arm/sysv.S==================== /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc. Copyright (c) 2011 Plausible Labs Cooperative, Inc. ARM Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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 __arm__ #define LIBFFI_ASM #include #include #include #include "internal.h" /* GCC 4.8 provides __ARM_ARCH; construct it otherwise. */ #ifndef __ARM_ARCH # if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ || defined(__ARM_ARCH_7EM__) # define __ARM_ARCH 7 # elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \ || defined(__ARM_ARCH_6M__) # define __ARM_ARCH 6 # elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ || defined(__ARM_ARCH_5TEJ__) # define __ARM_ARCH 5 # else # define __ARM_ARCH 4 # endif #endif /* Conditionally compile unwinder directives. */ #ifdef __ARM_EABI__ # define UNWIND(...) __VA_ARGS__ #else # define UNWIND(...) #endif #if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__) .cfi_sections .debug_frame #endif #define CONCAT(a, b) CONCAT2(a, b) #define CONCAT2(a, b) a ## b #ifdef __USER_LABEL_PREFIX__ # define CNAME(X) CONCAT (__USER_LABEL_PREFIX__, X) #else # define CNAME(X) X #endif #ifdef __ELF__ # define SIZE(X) .size CNAME(X), . - CNAME(X) # define TYPE(X, Y) .type CNAME(X), Y #else # define SIZE(X) # define TYPE(X, Y) #endif #define ARM_FUNC_START_LOCAL(name) \ .align 3; \ TYPE(CNAME(name), %function); \ CNAME(name): #define ARM_FUNC_START(name) \ .globl CNAME(name); \ FFI_HIDDEN(CNAME(name)); \ ARM_FUNC_START_LOCAL(name) #define ARM_FUNC_END(name) \ SIZE(name) /* Aid in defining a jump table with 8 bytes between entries. */ /* ??? The clang assembler doesn't handle .if with symbolic expressions. */ #ifdef __clang__ # define E(index) #else # define E(index) \ .if . - 0b - 8*index; \ .error "type table out of sync"; \ .endif #endif .text .syntax unified .arm #ifndef __clang__ /* We require interworking on LDM, which implies ARMv5T, which implies the existance of BLX. */ .arch armv5t #endif /* Note that we use STC and LDC to encode VFP instructions, so that we do not need ".fpu vfp", nor get that added to the object file attributes. These will not be executed unless the FFI_VFP abi is used. */ @ r0: stack @ r1: frame @ r2: fn @ r3: vfp_used ARM_FUNC_START(ffi_call_VFP) UNWIND(.fnstart) cfi_startproc cmp r3, #3 @ load only d0 if possible #ifdef __clang__ vldrle d0, [sp] vldmgt sp, {d0-d7} #else ldcle p11, cr0, [r0] @ vldrle d0, [sp] ldcgt p11, cr0, [r0], {16} @ vldmgt sp, {d0-d7} #endif add r0, r0, #64 @ discard the vfp register args /* FALLTHRU */ ARM_FUNC_END(ffi_call_VFP) ARM_FUNC_START(ffi_call_SYSV) stm r1, {fp, lr} mov fp, r1 @ This is a bit of a lie wrt the origin of the unwind info, but @ now we've got the usual frame pointer and two saved registers. UNWIND(.save {fp,lr}) UNWIND(.setfp fp, sp) cfi_def_cfa(fp, 8) cfi_rel_offset(fp, 0) cfi_rel_offset(lr, 4) mov sp, r0 @ install the stack pointer mov lr, r2 @ move the fn pointer out of the way ldr ip, [fp, #16] @ install the static chain ldmia sp!, {r0-r3} @ move first 4 parameters in registers. blx lr @ call fn @ Load r2 with the pointer to storage for the return value @ Load r3 with the return type code ldr r2, [fp, #8] ldr r3, [fp, #12] @ Deallocate the stack with the arguments. mov sp, fp cfi_def_cfa_register(sp) @ Store values stored in registers. .align 3 add pc, pc, r3, lsl #3 nop 0: E(ARM_TYPE_VFP_S) #ifdef __clang__ vstr s0, [r2] #else stc p10, cr0, [r2] @ vstr s0, [r2] #endif pop {fp,pc} E(ARM_TYPE_VFP_D) #ifdef __clang__ vstr d0, [r2] #else stc p11, cr0, [r2] @ vstr d0, [r2] #endif pop {fp,pc} E(ARM_TYPE_VFP_N) #ifdef __clang__ vstm r2, {d0-d3} #else stc p11, cr0, [r2], {8} @ vstm r2, {d0-d3} #endif pop {fp,pc} E(ARM_TYPE_INT64) str r1, [r2, #4] nop E(ARM_TYPE_INT) str r0, [r2] pop {fp,pc} E(ARM_TYPE_VOID) pop {fp,pc} nop E(ARM_TYPE_STRUCT) pop {fp,pc} cfi_endproc UNWIND(.fnend) ARM_FUNC_END(ffi_call_SYSV) /* int ffi_closure_inner_* (cif, fun, user_data, frame) */ ARM_FUNC_START(ffi_go_closure_SYSV) cfi_startproc stmdb sp!, {r0-r3} @ save argument regs cfi_adjust_cfa_offset(16) ldr r0, [ip, #4] @ load cif ldr r1, [ip, #8] @ load fun mov r2, ip @ load user_data b 0f cfi_endproc ARM_FUNC_END(ffi_go_closure_SYSV) ARM_FUNC_START(ffi_closure_SYSV) UNWIND(.fnstart) cfi_startproc stmdb sp!, {r0-r3} @ save argument regs cfi_adjust_cfa_offset(16) #if FFI_EXEC_TRAMPOLINE_TABLE ldr ip, [ip] @ ip points to the config page, dereference to get the ffi_closure* #endif ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] @ load cif ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] @ load fun ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] @ load user_data 0: add ip, sp, #16 @ compute entry sp sub sp, sp, #64+32 @ allocate frame cfi_adjust_cfa_offset(64+32) stmdb sp!, {ip,lr} /* Remember that EABI unwind info only applies at call sites. We need do nothing except note the save of the stack pointer and the link registers. */ UNWIND(.save {sp,lr}) cfi_adjust_cfa_offset(8) cfi_rel_offset(lr, 4) add r3, sp, #8 @ load frame bl CNAME(ffi_closure_inner_SYSV) @ Load values returned in registers. add r2, sp, #8+64 @ load result adr r3, CNAME(ffi_closure_ret) add pc, r3, r0, lsl #3 cfi_endproc UNWIND(.fnend) ARM_FUNC_END(ffi_closure_SYSV) ARM_FUNC_START(ffi_go_closure_VFP) cfi_startproc stmdb sp!, {r0-r3} @ save argument regs cfi_adjust_cfa_offset(16) ldr r0, [ip, #4] @ load cif ldr r1, [ip, #8] @ load fun mov r2, ip @ load user_data b 0f cfi_endproc ARM_FUNC_END(ffi_go_closure_VFP) ARM_FUNC_START(ffi_closure_VFP) UNWIND(.fnstart) cfi_startproc stmdb sp!, {r0-r3} @ save argument regs cfi_adjust_cfa_offset(16) #if FFI_EXEC_TRAMPOLINE_TABLE ldr ip, [ip] @ ip points to the config page, dereference to get the ffi_closure* #endif ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] @ load cif ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] @ load fun ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] @ load user_data 0: add ip, sp, #16 sub sp, sp, #64+32 @ allocate frame cfi_adjust_cfa_offset(64+32) #ifdef __clang__ vstm sp, {d0-d7} #else stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7} #endif stmdb sp!, {ip,lr} /* See above. */ UNWIND(.save {sp,lr}) cfi_adjust_cfa_offset(8) cfi_rel_offset(lr, 4) add r3, sp, #8 @ load frame bl CNAME(ffi_closure_inner_VFP) @ Load values returned in registers. add r2, sp, #8+64 @ load result adr r3, CNAME(ffi_closure_ret) add pc, r3, r0, lsl #3 cfi_endproc UNWIND(.fnend) ARM_FUNC_END(ffi_closure_VFP) /* Load values returned in registers for both closure entry points. Note that we use LDM with SP in the register set. This is deprecated by ARM, but not yet unpredictable. */ ARM_FUNC_START_LOCAL(ffi_closure_ret) cfi_startproc cfi_rel_offset(sp, 0) cfi_rel_offset(lr, 4) 0: E(ARM_TYPE_VFP_S) #ifdef __clang__ vldr s0, [r2] #else ldc p10, cr0, [r2] @ vldr s0, [r2] #endif ldm sp, {sp,pc} E(ARM_TYPE_VFP_D) #ifdef __clang__ vldr d0, [r2] #else ldc p11, cr0, [r2] @ vldr d0, [r2] #endif ldm sp, {sp,pc} E(ARM_TYPE_VFP_N) #ifdef __clang__ vldm r2, {d0-d3} #else ldc p11, cr0, [r2], {8} @ vldm r2, {d0-d3} #endif ldm sp, {sp,pc} E(ARM_TYPE_INT64) ldr r1, [r2, #4] nop E(ARM_TYPE_INT) ldr r0, [r2] ldm sp, {sp,pc} E(ARM_TYPE_VOID) ldm sp, {sp,pc} nop E(ARM_TYPE_STRUCT) ldm sp, {sp,pc} cfi_endproc ARM_FUNC_END(ffi_closure_ret) #if FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #include .align PAGE_MAX_SHIFT ARM_FUNC_START(ffi_closure_trampoline_table_page) .rept PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE adr ip, #-PAGE_MAX_SIZE @ the config page is PAGE_MAX_SIZE behind the trampoline page sub ip, #8 @ account for pc bias ldr pc, [ip, #4] @ jump to ffi_closure_SYSV or ffi_closure_VFP .endr ARM_FUNC_END(ffi_closure_trampoline_table_page) #endif #else ARM_FUNC_START(ffi_arm_trampoline) 0: adr ip, 0b ldr pc, 1f 1: .long 0 ARM_FUNC_END(ffi_arm_trampoline) #endif /* FFI_EXEC_TRAMPOLINE_TABLE */ #endif /* __arm__ */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",%progbits #endif ====================File: src/closures.c==================== /* ----------------------------------------------------------------------- closures.c - Copyright (c) 2019 Anthony Green Copyright (c) 2007, 2009, 2010 Red Hat, Inc. Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc Copyright (c) 2011 Plausible Labs Cooperative, Inc. Code to allocate and deallocate memory for closures. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #if defined __linux__ && !defined _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #ifdef __NetBSD__ #include #endif #if __NetBSD_Version__ - 0 >= 799007200 /* NetBSD with PROT_MPROTECT */ #include #include #include static const size_t overhead = (sizeof(max_align_t) > sizeof(void *) + sizeof(size_t)) ? sizeof(max_align_t) : sizeof(void *) + sizeof(size_t); #define ADD_TO_POINTER(p, d) ((void *)((uintptr_t)(p) + (d))) void * ffi_closure_alloc (size_t size, void **code) { static size_t page_size; size_t rounded_size; void *codeseg, *dataseg; int prot; /* Expect that PAX mprotect is active and a separate code mapping is necessary. */ if (!code) return NULL; /* Obtain system page size. */ if (!page_size) page_size = sysconf(_SC_PAGESIZE); /* Round allocation size up to the next page, keeping in mind the size field and pointer to code map. */ rounded_size = (size + overhead + page_size - 1) & ~(page_size - 1); /* Primary mapping is RW, but request permission to switch to PROT_EXEC later. */ prot = PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC); dataseg = mmap(NULL, rounded_size, prot, MAP_ANON | MAP_PRIVATE, -1, 0); if (dataseg == MAP_FAILED) return NULL; /* Create secondary mapping and switch it to RX. */ codeseg = mremap(dataseg, rounded_size, NULL, rounded_size, MAP_REMAPDUP); if (codeseg == MAP_FAILED) { munmap(dataseg, rounded_size); return NULL; } if (mprotect(codeseg, rounded_size, PROT_READ | PROT_EXEC) == -1) { munmap(codeseg, rounded_size); munmap(dataseg, rounded_size); return NULL; } /* Remember allocation size and location of the secondary mapping for ffi_closure_free. */ memcpy(dataseg, &rounded_size, sizeof(rounded_size)); memcpy(ADD_TO_POINTER(dataseg, sizeof(size_t)), &codeseg, sizeof(void *)); *code = ADD_TO_POINTER(codeseg, overhead); return ADD_TO_POINTER(dataseg, overhead); } void ffi_closure_free (void *ptr) { void *codeseg, *dataseg; size_t rounded_size; dataseg = ADD_TO_POINTER(ptr, -overhead); memcpy(&rounded_size, dataseg, sizeof(rounded_size)); memcpy(&codeseg, ADD_TO_POINTER(dataseg, sizeof(size_t)), sizeof(void *)); munmap(dataseg, rounded_size); munmap(codeseg, rounded_size); } #else /* !NetBSD with PROT_MPROTECT */ #if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE # if __linux__ && !defined(__ANDROID__) /* This macro indicates it may be forbidden to map anonymous memory with both write and execute permission. Code compiled when this option is defined will attempt to map such pages once, but if it fails, it falls back to creating a temporary file in a writable and executable filesystem and mapping pages from it into separate locations in the virtual memory space, one location writable and another executable. */ # define FFI_MMAP_EXEC_WRIT 1 # define HAVE_MNTENT 1 # endif # if defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__) /* Windows systems may have Data Execution Protection (DEP) enabled, which requires the use of VirtualMalloc/VirtualFree to alloc/free executable memory. */ # define FFI_MMAP_EXEC_WRIT 1 # endif #endif #if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX # if defined(__linux__) && !defined(__ANDROID__) /* When defined to 1 check for SELinux and if SELinux is active, don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that might cause audit messages. */ # define FFI_MMAP_EXEC_SELINUX 1 # endif #endif #if FFI_CLOSURES #if FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #include #include #include #include extern void *ffi_closure_trampoline_table_page; typedef struct ffi_trampoline_table ffi_trampoline_table; typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry; struct ffi_trampoline_table { /* contiguous writable and executable pages */ vm_address_t config_page; vm_address_t trampoline_page; /* free list tracking */ uint16_t free_count; ffi_trampoline_table_entry *free_list; ffi_trampoline_table_entry *free_list_pool; ffi_trampoline_table *prev; ffi_trampoline_table *next; }; struct ffi_trampoline_table_entry { void *(*trampoline) (void); ffi_trampoline_table_entry *next; }; /* Total number of trampolines that fit in one trampoline table */ #define FFI_TRAMPOLINE_COUNT (PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE) static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER; static ffi_trampoline_table *ffi_trampoline_tables = NULL; static ffi_trampoline_table * ffi_trampoline_table_alloc (void) { ffi_trampoline_table *table; vm_address_t config_page; vm_address_t trampoline_page; vm_address_t trampoline_page_template; vm_prot_t cur_prot; vm_prot_t max_prot; kern_return_t kt; uint16_t i; /* Allocate two pages -- a config page and a placeholder page */ config_page = 0x0; kt = vm_allocate (mach_task_self (), &config_page, PAGE_MAX_SIZE * 2, VM_FLAGS_ANYWHERE); if (kt != KERN_SUCCESS) return NULL; /* Remap the trampoline table on top of the placeholder page */ trampoline_page = config_page + PAGE_MAX_SIZE; trampoline_page_template = (vm_address_t)&ffi_closure_trampoline_table_page; #ifdef __arm__ /* ffi_closure_trampoline_table_page can be thumb-biased on some ARM archs */ trampoline_page_template &= ~1UL; #endif kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_MAX_SIZE, 0x0, VM_FLAGS_OVERWRITE, mach_task_self (), trampoline_page_template, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE); if (kt != KERN_SUCCESS) { vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2); return NULL; } /* We have valid trampoline and config pages */ table = calloc (1, sizeof (ffi_trampoline_table)); table->free_count = FFI_TRAMPOLINE_COUNT; table->config_page = config_page; table->trampoline_page = trampoline_page; /* Create and initialize the free list */ table->free_list_pool = calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry)); for (i = 0; i < table->free_count; i++) { ffi_trampoline_table_entry *entry = &table->free_list_pool[i]; entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE)); if (i < table->free_count - 1) entry->next = &table->free_list_pool[i + 1]; } table->free_list = table->free_list_pool; return table; } static void ffi_trampoline_table_free (ffi_trampoline_table *table) { /* Remove from the list */ if (table->prev != NULL) table->prev->next = table->next; if (table->next != NULL) table->next->prev = table->prev; /* Deallocate pages */ vm_deallocate (mach_task_self (), table->config_page, PAGE_MAX_SIZE * 2); /* Deallocate free list */ free (table->free_list_pool); free (table); } void * ffi_closure_alloc (size_t size, void **code) { /* Create the closure */ ffi_closure *closure = malloc (size); if (closure == NULL) return NULL; pthread_mutex_lock (&ffi_trampoline_lock); /* Check for an active trampoline table with available entries. */ ffi_trampoline_table *table = ffi_trampoline_tables; if (table == NULL || table->free_list == NULL) { table = ffi_trampoline_table_alloc (); if (table == NULL) { pthread_mutex_unlock (&ffi_trampoline_lock); free (closure); return NULL; } /* Insert the new table at the top of the list */ table->next = ffi_trampoline_tables; if (table->next != NULL) table->next->prev = table; ffi_trampoline_tables = table; } /* Claim the free entry */ ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list; ffi_trampoline_tables->free_list = entry->next; ffi_trampoline_tables->free_count--; entry->next = NULL; pthread_mutex_unlock (&ffi_trampoline_lock); /* Initialize the return values */ *code = entry->trampoline; closure->trampoline_table = table; closure->trampoline_table_entry = entry; return closure; } void ffi_closure_free (void *ptr) { ffi_closure *closure = ptr; pthread_mutex_lock (&ffi_trampoline_lock); /* Fetch the table and entry references */ ffi_trampoline_table *table = closure->trampoline_table; ffi_trampoline_table_entry *entry = closure->trampoline_table_entry; /* Return the entry to the free list */ entry->next = table->free_list; table->free_list = entry; table->free_count++; /* If all trampolines within this table are free, and at least one other table exists, deallocate * the table */ if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) { ffi_trampoline_table_free (table); } else if (ffi_trampoline_tables != table) { /* Otherwise, bump this table to the top of the list */ table->prev = NULL; table->next = ffi_trampoline_tables; if (ffi_trampoline_tables != NULL) ffi_trampoline_tables->prev = table; ffi_trampoline_tables = table; } pthread_mutex_unlock (&ffi_trampoline_lock); /* Free the closure */ free (closure); } #endif // Per-target implementation; It's unclear what can reasonable be shared between two OS/architecture implementations. #elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */ #define USE_LOCKS 1 #define USE_DL_PREFIX 1 #ifdef __GNUC__ #ifndef USE_BUILTIN_FFS #define USE_BUILTIN_FFS 1 #endif #endif /* We need to use mmap, not sbrk. */ #define HAVE_MORECORE 0 /* We could, in theory, support mremap, but it wouldn't buy us anything. */ #define HAVE_MREMAP 0 /* We have no use for this, so save some code and data. */ #define NO_MALLINFO 1 /* We need all allocations to be in regular segments, otherwise we lose track of the corresponding code address. */ #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T /* Don't allocate more than a page unless needed. */ #define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize) #include #include #include #include #ifndef _MSC_VER #include #endif #include #include #if !defined(X86_WIN32) && !defined(X86_WIN64) && !defined(_M_ARM64) #ifdef HAVE_MNTENT #include #endif /* HAVE_MNTENT */ #include #include /* We don't want sys/mman.h to be included after we redefine mmap and dlmunmap. */ #include #define LACKS_SYS_MMAN_H 1 #if FFI_MMAP_EXEC_SELINUX #include #include static int selinux_enabled = -1; static int selinux_enabled_check (void) { struct statfs sfs; FILE *f; char *buf = NULL; size_t len = 0; if (statfs ("/selinux", &sfs) >= 0 && (unsigned int) sfs.f_type == 0xf97cff8cU) return 1; f = fopen ("/proc/mounts", "r"); if (f == NULL) return 0; while (getline (&buf, &len, f) >= 0) { char *p = strchr (buf, ' '); if (p == NULL) break; p = strchr (p + 1, ' '); if (p == NULL) break; if (strncmp (p + 1, "selinuxfs ", 10) == 0) { free (buf); fclose (f); return 1; } } free (buf); fclose (f); return 0; } #define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \ : (selinux_enabled = selinux_enabled_check ())) #else #define is_selinux_enabled() 0 #endif /* !FFI_MMAP_EXEC_SELINUX */ /* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */ #ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX #include static int emutramp_enabled = -1; static int emutramp_enabled_check (void) { char *buf = NULL; size_t len = 0; FILE *f; int ret; f = fopen ("/proc/self/status", "r"); if (f == NULL) return 0; ret = 0; while (getline (&buf, &len, f) != -1) if (!strncmp (buf, "PaX:", 4)) { char emutramp; if (sscanf (buf, "%*s %*c%c", &emutramp) == 1) ret = (emutramp == 'E'); break; } free (buf); fclose (f); return ret; } #define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \ : (emutramp_enabled = emutramp_enabled_check ())) #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */ #elif defined (__CYGWIN__) || defined(__INTERIX) #include /* Cygwin is Linux-like, but not quite that Linux-like. */ #define is_selinux_enabled() 0 #endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */ #ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX #define is_emutramp_enabled() 0 #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */ /* Declare all functions defined in dlmalloc.c as static. */ static void *dlmalloc(size_t); static void dlfree(void*); static void *dlcalloc(size_t, size_t) MAYBE_UNUSED; static void *dlrealloc(void *, size_t) MAYBE_UNUSED; static void *dlmemalign(size_t, size_t) MAYBE_UNUSED; static void *dlvalloc(size_t) MAYBE_UNUSED; static int dlmallopt(int, int) MAYBE_UNUSED; static size_t dlmalloc_footprint(void) MAYBE_UNUSED; static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED; static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED; static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED; static void *dlpvalloc(size_t) MAYBE_UNUSED; static int dlmalloc_trim(size_t) MAYBE_UNUSED; static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED; static void dlmalloc_stats(void) MAYBE_UNUSED; #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) /* Use these for mmap and munmap within dlmalloc.c. */ static void *dlmmap(void *, size_t, int, int, int, off_t); static int dlmunmap(void *, size_t); #endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */ #define mmap dlmmap #define munmap dlmunmap #include "dlmalloc.c" #undef mmap #undef munmap #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) /* A mutex used to synchronize access to *exec* variables in this file. */ static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER; /* A file descriptor of a temporary file from which we'll map executable pages. */ static int execfd = -1; /* The amount of space already allocated from the temporary file. */ static size_t execsize = 0; /* Open a temporary file name, and immediately unlink it. */ static int open_temp_exec_file_name (char *name, int flags) { int fd; #ifdef HAVE_MKOSTEMP fd = mkostemp (name, flags); #else fd = mkstemp (name); #endif if (fd != -1) unlink (name); return fd; } /* Open a temporary file in the named directory. */ static int open_temp_exec_file_dir (const char *dir) { static const char suffix[] = "/ffiXXXXXX"; int lendir, flags; char *tempname; #ifdef O_TMPFILE int fd; #endif #ifdef O_CLOEXEC flags = O_CLOEXEC; #else flags = 0; #endif #ifdef O_TMPFILE fd = open (dir, flags | O_RDWR | O_EXCL | O_TMPFILE, 0700); /* If the running system does not support the O_TMPFILE flag then retry without it. */ if (fd != -1 || (errno != EINVAL && errno != EISDIR && errno != EOPNOTSUPP)) { return fd; } else { errno = 0; } #endif lendir = (int) strlen (dir); tempname = __builtin_alloca (lendir + sizeof (suffix)); if (!tempname) return -1; memcpy (tempname, dir, lendir); memcpy (tempname + lendir, suffix, sizeof (suffix)); return open_temp_exec_file_name (tempname, flags); } /* Open a temporary file in the directory in the named environment variable. */ static int open_temp_exec_file_env (const char *envvar) { const char *value = getenv (envvar); if (!value) return -1; return open_temp_exec_file_dir (value); } #ifdef HAVE_MNTENT /* Open a temporary file in an executable and writable mount point listed in the mounts file. Subsequent calls with the same mounts keep searching for mount points in the same file. Providing NULL as the mounts file closes the file. */ static int open_temp_exec_file_mnt (const char *mounts) { static const char *last_mounts; static FILE *last_mntent; if (mounts != last_mounts) { if (last_mntent) endmntent (last_mntent); last_mounts = mounts; if (mounts) last_mntent = setmntent (mounts, "r"); else last_mntent = NULL; } if (!last_mntent) return -1; for (;;) { int fd; struct mntent mnt; char buf[MAXPATHLEN * 3]; if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)) == NULL) return -1; if (hasmntopt (&mnt, "ro") || hasmntopt (&mnt, "noexec") || access (mnt.mnt_dir, W_OK)) continue; fd = open_temp_exec_file_dir (mnt.mnt_dir); if (fd != -1) return fd; } } #endif /* HAVE_MNTENT */ /* Instructions to look for a location to hold a temporary file that can be mapped in for execution. */ static struct { int (*func)(const char *); const char *arg; int repeat; } open_temp_exec_file_opts[] = { { open_temp_exec_file_env, "TMPDIR", 0 }, { open_temp_exec_file_dir, "/tmp", 0 }, { open_temp_exec_file_dir, "/var/tmp", 0 }, { open_temp_exec_file_dir, "/dev/shm", 0 }, { open_temp_exec_file_env, "HOME", 0 }, #ifdef HAVE_MNTENT { open_temp_exec_file_mnt, "/etc/mtab", 1 }, { open_temp_exec_file_mnt, "/proc/mounts", 1 }, #endif /* HAVE_MNTENT */ }; /* Current index into open_temp_exec_file_opts. */ static int open_temp_exec_file_opts_idx = 0; /* Reset a current multi-call func, then advances to the next entry. If we're at the last, go back to the first and return nonzero, otherwise return zero. */ static int open_temp_exec_file_opts_next (void) { if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat) open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL); open_temp_exec_file_opts_idx++; if (open_temp_exec_file_opts_idx == (sizeof (open_temp_exec_file_opts) / sizeof (*open_temp_exec_file_opts))) { open_temp_exec_file_opts_idx = 0; return 1; } return 0; } /* Return a file descriptor of a temporary zero-sized file in a writable and executable filesystem. */ static int open_temp_exec_file (void) { int fd; do { fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg); if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat || fd == -1) { if (open_temp_exec_file_opts_next ()) break; } } while (fd == -1); return fd; } /* We need to allocate space in a file that will be backing a writable mapping. Several problems exist with the usual approaches: - fallocate() is Linux-only - posix_fallocate() is not available on all platforms - ftruncate() does not allocate space on filesystems with sparse files Failure to allocate the space will cause SIGBUS to be thrown when the mapping is subsequently written to. */ static int allocate_space (int fd, off_t offset, off_t len) { static size_t page_size; /* Obtain system page size. */ if (!page_size) page_size = sysconf(_SC_PAGESIZE); unsigned char buf[page_size]; memset (buf, 0, page_size); while (len > 0) { off_t to_write = (len < page_size) ? len : page_size; if (write (fd, buf, to_write) < to_write) return -1; len -= to_write; } return 0; } /* Map in a chunk of memory from the temporary exec file into separate locations in the virtual memory address space, one writable and one executable. Returns the address of the writable portion, after storing an offset to the corresponding executable portion at the last word of the requested chunk. */ static void * dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset) { void *ptr; if (execfd == -1) { open_temp_exec_file_opts_idx = 0; retry_open: execfd = open_temp_exec_file (); if (execfd == -1) return MFAIL; } offset = execsize; if (allocate_space (execfd, offset, length)) return MFAIL; flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS); flags |= MAP_SHARED; ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC, flags, execfd, offset); if (ptr == MFAIL) { if (!offset) { close (execfd); goto retry_open; } if (ftruncate (execfd, offset) != 0) { /* Fixme : Error logs can be added here. Returning an error for * ftruncte() will not add any advantage as it is being * validating in the error case. */ } return MFAIL; } else if (!offset && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat) open_temp_exec_file_opts_next (); start = mmap (start, length, prot, flags, execfd, offset); if (start == MFAIL) { munmap (ptr, length); if (ftruncate (execfd, offset) != 0) { /* Fixme : Error logs can be added here. Returning an error for * ftruncte() will not add any advantage as it is being * validating in the error case. */ } return start; } mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start; execsize += length; return start; } /* Map in a writable and executable chunk of memory if possible. Failing that, fall back to dlmmap_locked. */ static void * dlmmap (void *start, size_t length, int prot, int flags, int fd, off_t offset) { void *ptr; assert (start == NULL && length % malloc_getpagesize == 0 && prot == (PROT_READ | PROT_WRITE) && flags == (MAP_PRIVATE | MAP_ANONYMOUS) && fd == -1 && offset == 0); if (execfd == -1 && is_emutramp_enabled ()) { ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset); return ptr; } if (execfd == -1 && !is_selinux_enabled ()) { ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset); if (ptr != MFAIL || (errno != EPERM && errno != EACCES)) /* Cool, no need to mess with separate segments. */ return ptr; /* If MREMAP_DUP is ever introduced and implemented, try mmap with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with MREMAP_DUP and prot at this point. */ } if (execsize == 0 || execfd == -1) { pthread_mutex_lock (&open_temp_exec_file_mutex); ptr = dlmmap_locked (start, length, prot, flags, offset); pthread_mutex_unlock (&open_temp_exec_file_mutex); return ptr; } return dlmmap_locked (start, length, prot, flags, offset); } /* Release memory at the given address, as well as the corresponding executable page if it's separate. */ static int dlmunmap (void *start, size_t length) { /* We don't bother decreasing execsize or truncating the file, since we can't quite tell whether we're unmapping the end of the file. We don't expect frequent deallocation anyway. If we did, we could locate pages in the file by writing to the pages being deallocated and checking that the file contents change. Yuck. */ msegmentptr seg = segment_holding (gm, start); void *code; if (seg && (code = add_segment_exec_offset (start, seg)) != start) { int ret = munmap (code, length); if (ret) return ret; } return munmap (start, length); } #if FFI_CLOSURE_FREE_CODE /* Return segment holding given code address. */ static msegmentptr segment_holding_code (mstate m, char* addr) { msegmentptr sp = &m->seg; for (;;) { if (addr >= add_segment_exec_offset (sp->base, sp) && addr < add_segment_exec_offset (sp->base, sp) + sp->size) return sp; if ((sp = sp->next) == 0) return 0; } } #endif #endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */ /* Allocate a chunk of memory with the given size. Returns a pointer to the writable address, and sets *CODE to the executable corresponding virtual address. */ void * ffi_closure_alloc (size_t size, void **code) { void *ptr; if (!code) return NULL; ptr = dlmalloc (size); if (ptr) { msegmentptr seg = segment_holding (gm, ptr); *code = add_segment_exec_offset (ptr, seg); } return ptr; } void * ffi_data_to_code_pointer (void *data) { msegmentptr seg = segment_holding (gm, data); /* We expect closures to be allocated with ffi_closure_alloc(), in which case seg will be non-NULL. However, some users take on the burden of managing this memory themselves, in which case this we'll just return data. */ if (seg) return add_segment_exec_offset (data, seg); else return data; } /* Release a chunk of memory allocated with ffi_closure_alloc. If FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the writable or the executable address given. Otherwise, only the writable address can be provided here. */ void ffi_closure_free (void *ptr) { #if FFI_CLOSURE_FREE_CODE msegmentptr seg = segment_holding_code (gm, ptr); if (seg) ptr = sub_segment_exec_offset (ptr, seg); #endif dlfree (ptr); } # else /* ! FFI_MMAP_EXEC_WRIT */ /* On many systems, memory returned by malloc is writable and executable, so just use it. */ #include void * ffi_closure_alloc (size_t size, void **code) { if (!code) return NULL; return *code = malloc (size); } void ffi_closure_free (void *ptr) { free (ptr); } void * ffi_data_to_code_pointer (void *data) { return data; } # endif /* ! FFI_MMAP_EXEC_WRIT */ #endif /* FFI_CLOSURES */ #endif /* NetBSD with PROT_MPROTECT */ ====================File: src/java_raw_api.c==================== /* ----------------------------------------------------------------------- java_raw_api.c - Copyright (c) 1999, 2007, 2008 Red Hat, Inc. Cloned from raw_api.c Raw_api.c author: Kresten Krab Thorup Java_raw_api.c author: Hans-J. Boehm $Id $ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ /* This defines a Java- and 64-bit specific variant of the raw API. */ /* It assumes that "raw" argument blocks look like Java stacks on a */ /* 64-bit machine. Arguments that can be stored in a single stack */ /* stack slots (longs, doubles) occupy 128 bits, but only the first */ /* 64 bits are actually used. */ #include #include #include #if !defined(NO_JAVA_RAW_API) size_t ffi_java_raw_size (ffi_cif *cif) { size_t result = 0; int i; ffi_type **at = cif->arg_types; for (i = cif->nargs-1; i >= 0; i--, at++) { switch((*at) -> type) { case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: case FFI_TYPE_DOUBLE: result += 2 * FFI_SIZEOF_JAVA_RAW; break; case FFI_TYPE_STRUCT: /* No structure parameters in Java. */ abort(); case FFI_TYPE_COMPLEX: /* Not supported yet. */ abort(); default: result += FFI_SIZEOF_JAVA_RAW; } } return result; } void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) { unsigned i; ffi_type **tp = cif->arg_types; #if WORDS_BIGENDIAN for (i = 0; i < cif->nargs; i++, tp++, args++) { switch ((*tp)->type) { case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: *args = (void*) ((char*)(raw++) + 3); break; case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: *args = (void*) ((char*)(raw++) + 2); break; #if FFI_SIZEOF_JAVA_RAW == 8 case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: case FFI_TYPE_DOUBLE: *args = (void *)raw; raw += 2; break; #endif case FFI_TYPE_POINTER: *args = (void*) &(raw++)->ptr; break; case FFI_TYPE_COMPLEX: /* Not supported yet. */ abort(); default: *args = raw; raw += FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw); } } #else /* WORDS_BIGENDIAN */ #if !PDP /* then assume little endian */ for (i = 0; i < cif->nargs; i++, tp++, args++) { #if FFI_SIZEOF_JAVA_RAW == 8 switch((*tp)->type) { case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: case FFI_TYPE_DOUBLE: *args = (void*) raw; raw += 2; break; case FFI_TYPE_COMPLEX: /* Not supported yet. */ abort(); default: *args = (void*) raw++; } #else /* FFI_SIZEOF_JAVA_RAW != 8 */ *args = (void*) raw; raw += FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw); #endif /* FFI_SIZEOF_JAVA_RAW == 8 */ } #else #error "pdp endian not supported" #endif /* ! PDP */ #endif /* WORDS_BIGENDIAN */ } void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) { unsigned i; ffi_type **tp = cif->arg_types; for (i = 0; i < cif->nargs; i++, tp++, args++) { switch ((*tp)->type) { case FFI_TYPE_UINT8: #if WORDS_BIGENDIAN *(UINT32*)(raw++) = *(UINT8*) (*args); #else (raw++)->uint = *(UINT8*) (*args); #endif break; case FFI_TYPE_SINT8: #if WORDS_BIGENDIAN *(SINT32*)(raw++) = *(SINT8*) (*args); #else (raw++)->sint = *(SINT8*) (*args); #endif break; case FFI_TYPE_UINT16: #if WORDS_BIGENDIAN *(UINT32*)(raw++) = *(UINT16*) (*args); #else (raw++)->uint = *(UINT16*) (*args); #endif break; case FFI_TYPE_SINT16: #if WORDS_BIGENDIAN *(SINT32*)(raw++) = *(SINT16*) (*args); #else (raw++)->sint = *(SINT16*) (*args); #endif break; case FFI_TYPE_UINT32: #if WORDS_BIGENDIAN *(UINT32*)(raw++) = *(UINT32*) (*args); #else (raw++)->uint = *(UINT32*) (*args); #endif break; case FFI_TYPE_SINT32: #if WORDS_BIGENDIAN *(SINT32*)(raw++) = *(SINT32*) (*args); #else (raw++)->sint = *(SINT32*) (*args); #endif break; case FFI_TYPE_FLOAT: (raw++)->flt = *(FLOAT32*) (*args); break; #if FFI_SIZEOF_JAVA_RAW == 8 case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: case FFI_TYPE_DOUBLE: raw->uint = *(UINT64*) (*args); raw += 2; break; #endif case FFI_TYPE_POINTER: (raw++)->ptr = **(void***) args; break; default: #if FFI_SIZEOF_JAVA_RAW == 8 FFI_ASSERT(0); /* Should have covered all cases */ #else memcpy ((void*) raw->data, (void*)*args, (*tp)->size); raw += FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw); #endif } } } #if !FFI_NATIVE_RAW_API static void ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue) { #if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8 switch (cif->rtype->type) { case FFI_TYPE_UINT8: case FFI_TYPE_UINT16: case FFI_TYPE_UINT32: *(UINT64 *)rvalue <<= 32; break; case FFI_TYPE_SINT8: case FFI_TYPE_SINT16: case FFI_TYPE_SINT32: case FFI_TYPE_INT: #if FFI_SIZEOF_JAVA_RAW == 4 case FFI_TYPE_POINTER: #endif *(SINT64 *)rvalue <<= 32; break; case FFI_TYPE_COMPLEX: /* Not supported yet. */ abort(); default: break; } #endif } static void ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue) { #if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8 switch (cif->rtype->type) { case FFI_TYPE_UINT8: case FFI_TYPE_UINT16: case FFI_TYPE_UINT32: *(UINT64 *)rvalue >>= 32; break; case FFI_TYPE_SINT8: case FFI_TYPE_SINT16: case FFI_TYPE_SINT32: case FFI_TYPE_INT: *(SINT64 *)rvalue >>= 32; break; case FFI_TYPE_COMPLEX: /* Not supported yet. */ abort(); default: break; } #endif } /* This is a generic definition of ffi_raw_call, to be used if the * native system does not provide a machine-specific implementation. * Having this, allows code to be written for the raw API, without * the need for system-specific code to handle input in that format; * these following couple of functions will handle the translation forth * and back automatically. */ void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_java_raw *raw) { void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); ffi_java_raw_to_ptrarray (cif, raw, avalue); ffi_call (cif, fn, rvalue, avalue); ffi_java_rvalue_to_raw (cif, rvalue); } #if FFI_CLOSURES /* base system provides closures */ static void ffi_java_translate_args (ffi_cif *cif, void *rvalue, void **avalue, void *user_data) { ffi_java_raw *raw = (ffi_java_raw*)alloca (ffi_java_raw_size (cif)); ffi_raw_closure *cl = (ffi_raw_closure*)user_data; ffi_java_ptrarray_to_raw (cif, avalue, raw); (*cl->fun) (cif, rvalue, (ffi_raw*)raw, cl->user_data); ffi_java_raw_to_rvalue (cif, rvalue); } ffi_status ffi_prep_java_raw_closure_loc (ffi_java_raw_closure* cl, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data, void *codeloc) { ffi_status status; status = ffi_prep_closure_loc ((ffi_closure*) cl, cif, &ffi_java_translate_args, codeloc, codeloc); if (status == FFI_OK) { cl->fun = fun; cl->user_data = user_data; } return status; } /* Again, here is the generic version of ffi_prep_raw_closure, which * will install an intermediate "hub" for translation of arguments from * the pointer-array format, to the raw format */ ffi_status ffi_prep_java_raw_closure (ffi_java_raw_closure* cl, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data) { return ffi_prep_java_raw_closure_loc (cl, cif, fun, user_data, cl); } #endif /* FFI_CLOSURES */ #endif /* !FFI_NATIVE_RAW_API */ #endif /* !NO_JAVA_RAW_API */ ====================File: src/powerpc/aix.S==================== /* ----------------------------------------------------------------------- aix.S - Copyright (c) 2002, 2009 Free Software Foundation, Inc. based on darwin.S by John Hornkvist PowerPC Assembly glue. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ .set r0,0 .set r1,1 .set r2,2 .set r3,3 .set r4,4 .set r5,5 .set r6,6 .set r7,7 .set r8,8 .set r9,9 .set r10,10 .set r11,11 .set r12,12 .set r13,13 .set r14,14 .set r15,15 .set r16,16 .set r17,17 .set r18,18 .set r19,19 .set r20,20 .set r21,21 .set r22,22 .set r23,23 .set r24,24 .set r25,25 .set r26,26 .set r27,27 .set r28,28 .set r29,29 .set r30,30 .set r31,31 .set f0,0 .set f1,1 .set f2,2 .set f3,3 .set f4,4 .set f5,5 .set f6,6 .set f7,7 .set f8,8 .set f9,9 .set f10,10 .set f11,11 .set f12,12 .set f13,13 .set f14,14 .set f15,15 .set f16,16 .set f17,17 .set f18,18 .set f19,19 .set f20,20 .set f21,21 .extern .ffi_prep_args #define LIBFFI_ASM #include #include #define JUMPTARGET(name) name #define L(x) x .file "aix.S" .toc /* void ffi_call_AIX(extended_cif *ecif, unsigned long bytes, * unsigned int flags, unsigned int *rvalue, * void (*fn)(), * void (*prep_args)(extended_cif*, unsigned *const)); * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args */ .csect .text[PR] .align 2 .globl ffi_call_AIX .globl .ffi_call_AIX .csect ffi_call_AIX[DS] ffi_call_AIX: #ifdef __64BIT__ .llong .ffi_call_AIX, TOC[tc0], 0 .csect .text[PR] .ffi_call_AIX: .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0 .bf __LINE__ .line 1 LFB..0: /* Save registers we use. */ mflr r0 std r28,-32(r1) std r29,-24(r1) std r30,-16(r1) std r31, -8(r1) std r0, 16(r1) LCFI..0: mr r28, r1 /* our AP. */ stdux r1, r1, r4 LCFI..1: /* Save arguments over call... */ mr r31, r5 /* flags, */ mr r30, r6 /* rvalue, */ mr r29, r7 /* function address. */ std r2, 40(r1) /* Call ffi_prep_args. */ mr r4, r1 bl .ffi_prep_args nop /* Now do the call. */ ld r0, 0(r29) ld r2, 8(r29) ld r11, 16(r29) /* Set up cr1 with bits 4-7 of the flags. */ mtcrf 0x40, r31 mtctr r0 /* Load all those argument registers. */ /* We have set up a nice stack frame, just load it into registers. */ ld r3, 40+(1*8)(r1) ld r4, 40+(2*8)(r1) ld r5, 40+(3*8)(r1) ld r6, 40+(4*8)(r1) nop ld r7, 40+(5*8)(r1) ld r8, 40+(6*8)(r1) ld r9, 40+(7*8)(r1) ld r10,40+(8*8)(r1) L1: /* Load all the FP registers. */ bf 6,L2 /* 2f + 0x18 */ lfd f1,-32-(13*8)(r28) lfd f2,-32-(12*8)(r28) lfd f3,-32-(11*8)(r28) lfd f4,-32-(10*8)(r28) nop lfd f5,-32-(9*8)(r28) lfd f6,-32-(8*8)(r28) lfd f7,-32-(7*8)(r28) lfd f8,-32-(6*8)(r28) nop lfd f9,-32-(5*8)(r28) lfd f10,-32-(4*8)(r28) lfd f11,-32-(3*8)(r28) lfd f12,-32-(2*8)(r28) nop lfd f13,-32-(1*8)(r28) L2: /* Make the call. */ bctrl ld r2, 40(r1) /* Now, deal with the return value. */ mtcrf 0x01, r31 bt 30, L(done_return_value) bt 29, L(fp_return_value) std r3, 0(r30) /* Fall through... */ L(done_return_value): /* Restore the registers we used and return. */ mr r1, r28 ld r0, 16(r28) ld r28, -32(r1) mtlr r0 ld r29, -24(r1) ld r30, -16(r1) ld r31, -8(r1) blr L(fp_return_value): bf 28, L(float_return_value) stfd f1, 0(r30) bf 31, L(done_return_value) stfd f2, 8(r30) b L(done_return_value) L(float_return_value): stfs f1, 0(r30) b L(done_return_value) LFE..0: #else /* ! __64BIT__ */ .long .ffi_call_AIX, TOC[tc0], 0 .csect .text[PR] .ffi_call_AIX: .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0 .bf __LINE__ .line 1 LFB..0: /* Save registers we use. */ mflr r0 stw r28,-16(r1) stw r29,-12(r1) stw r30, -8(r1) stw r31, -4(r1) stw r0, 8(r1) LCFI..0: mr r28, r1 /* out AP. */ stwux r1, r1, r4 LCFI..1: /* Save arguments over call... */ mr r31, r5 /* flags, */ mr r30, r6 /* rvalue, */ mr r29, r7 /* function address, */ stw r2, 20(r1) /* Call ffi_prep_args. */ mr r4, r1 bl .ffi_prep_args nop /* Now do the call. */ lwz r0, 0(r29) lwz r2, 4(r29) lwz r11, 8(r29) /* Set up cr1 with bits 4-7 of the flags. */ mtcrf 0x40, r31 mtctr r0 /* Load all those argument registers. */ /* We have set up a nice stack frame, just load it into registers. */ lwz r3, 20+(1*4)(r1) lwz r4, 20+(2*4)(r1) lwz r5, 20+(3*4)(r1) lwz r6, 20+(4*4)(r1) nop lwz r7, 20+(5*4)(r1) lwz r8, 20+(6*4)(r1) lwz r9, 20+(7*4)(r1) lwz r10,20+(8*4)(r1) L1: /* Load all the FP registers. */ bf 6,L2 /* 2f + 0x18 */ lfd f1,-16-(13*8)(r28) lfd f2,-16-(12*8)(r28) lfd f3,-16-(11*8)(r28) lfd f4,-16-(10*8)(r28) nop lfd f5,-16-(9*8)(r28) lfd f6,-16-(8*8)(r28) lfd f7,-16-(7*8)(r28) lfd f8,-16-(6*8)(r28) nop lfd f9,-16-(5*8)(r28) lfd f10,-16-(4*8)(r28) lfd f11,-16-(3*8)(r28) lfd f12,-16-(2*8)(r28) nop lfd f13,-16-(1*8)(r28) L2: /* Make the call. */ bctrl lwz r2, 20(r1) /* Now, deal with the return value. */ mtcrf 0x01, r31 bt 30, L(done_return_value) bt 29, L(fp_return_value) stw r3, 0(r30) bf 28, L(done_return_value) stw r4, 4(r30) /* Fall through... */ L(done_return_value): /* Restore the registers we used and return. */ mr r1, r28 lwz r0, 8(r28) lwz r28,-16(r1) mtlr r0 lwz r29,-12(r1) lwz r30, -8(r1) lwz r31, -4(r1) blr L(fp_return_value): bf 28, L(float_return_value) stfd f1, 0(r30) b L(done_return_value) L(float_return_value): stfs f1, 0(r30) b L(done_return_value) LFE..0: #endif .ef __LINE__ .long 0 .byte 0,0,0,1,128,4,0,0 /* END(ffi_call_AIX) */ /* void ffi_call_go_AIX(extended_cif *ecif, unsigned long bytes, * unsigned int flags, unsigned int *rvalue, * void (*fn)(), * void (*prep_args)(extended_cif*, unsigned *const), * void *closure); * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args, r9=closure */ .csect .text[PR] .align 2 .globl ffi_call_go_AIX .globl .ffi_call_go_AIX .csect ffi_call_go_AIX[DS] ffi_call_go_AIX: #ifdef __64BIT__ .llong .ffi_call_go_AIX, TOC[tc0], 0 .csect .text[PR] .ffi_call_go_AIX: .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1 .bf __LINE__ .line 1 LFB..1: /* Save registers we use. */ mflr r0 std r28,-32(r1) std r29,-24(r1) std r30,-16(r1) std r31, -8(r1) std r9, 8(r1) /* closure, saved in cr field. */ std r0, 16(r1) LCFI..2: mr r28, r1 /* our AP. */ stdux r1, r1, r4 LCFI..3: /* Save arguments over call... */ mr r31, r5 /* flags, */ mr r30, r6 /* rvalue, */ mr r29, r7 /* function address, */ std r2, 40(r1) /* Call ffi_prep_args. */ mr r4, r1 bl .ffi_prep_args nop /* Now do the call. */ ld r0, 0(r29) ld r2, 8(r29) ld r11, 8(r28) /* closure */ /* Set up cr1 with bits 4-7 of the flags. */ mtcrf 0x40, r31 mtctr r0 /* Load all those argument registers. */ /* We have set up a nice stack frame, just load it into registers. */ ld r3, 40+(1*8)(r1) ld r4, 40+(2*8)(r1) ld r5, 40+(3*8)(r1) ld r6, 40+(4*8)(r1) nop ld r7, 40+(5*8)(r1) ld r8, 40+(6*8)(r1) ld r9, 40+(7*8)(r1) ld r10,40+(8*8)(r1) b L1 LFE..1: #else /* ! __64BIT__ */ .long .ffi_call_go_AIX, TOC[tc0], 0 .csect .text[PR] .ffi_call_go_AIX: .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1 .bf __LINE__ .line 1 /* Save registers we use. */ LFB..1: mflr r0 stw r28,-16(r1) stw r29,-12(r1) stw r30, -8(r1) stw r31, -4(r1) stw r9, 4(r1) /* closure, saved in cr field. */ stw r0, 8(r1) LCFI..2: mr r28, r1 /* out AP. */ stwux r1, r1, r4 LCFI..3: /* Save arguments over call... */ mr r31, r5 /* flags, */ mr r30, r6 /* rvalue, */ mr r29, r7 /* function address, */ stw r2, 20(r1) /* Call ffi_prep_args. */ mr r4, r1 bl .ffi_prep_args nop /* Now do the call. */ lwz r0, 0(r29) lwz r2, 4(r29) lwz r11, 4(r28) /* closure */ /* Set up cr1 with bits 4-7 of the flags. */ mtcrf 0x40, r31 mtctr r0 /* Load all those argument registers. */ /* We have set up a nice stack frame, just load it into registers. */ lwz r3, 20+(1*4)(r1) lwz r4, 20+(2*4)(r1) lwz r5, 20+(3*4)(r1) lwz r6, 20+(4*4)(r1) nop lwz r7, 20+(5*4)(r1) lwz r8, 20+(6*4)(r1) lwz r9, 20+(7*4)(r1) lwz r10,20+(8*4)(r1) b L1 LFE..1: #endif .ef __LINE__ .long 0 .byte 0,0,0,1,128,4,0,0 /* END(ffi_call_go_AIX) */ .csect .text[PR] .align 2 .globl ffi_call_DARWIN .globl .ffi_call_DARWIN .csect ffi_call_DARWIN[DS] ffi_call_DARWIN: #ifdef __64BIT__ .llong .ffi_call_DARWIN, TOC[tc0], 0 #else .long .ffi_call_DARWIN, TOC[tc0], 0 #endif .csect .text[PR] .ffi_call_DARWIN: blr .long 0 .byte 0,0,0,0,0,0,0,0 /* END(ffi_call_DARWIN) */ /* EH frame stuff. */ #define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */ #ifdef __64BIT__ #define PTRSIZE 8 #define LOG2_PTRSIZE 3 #define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */ #define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */ #else #define PTRSIZE 4 #define LOG2_PTRSIZE 2 #define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */ #define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */ #endif .csect _unwind.ro_[RO],4 .align LOG2_PTRSIZE .globl _GLOBAL__F_libffi_src_powerpc_aix _GLOBAL__F_libffi_src_powerpc_aix: Lframe..1: .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */ LSCIE..1: .vbyte 4,0 /* CIE Identifier Tag */ .byte 0x3 /* CIE Version */ .byte "zR" /* CIE Augmentation */ .byte 0 .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */ .byte 0x41 /* CIE RA Column */ .byte 0x1 /* uleb128 0x1; Augmentation size */ .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */ .byte 0xc /* DW_CFA_def_cfa */ .byte 0x1 /* uleb128 0x1; Register r1 */ .byte 0 /* uleb128 0x0; Offset 0 */ .align LOG2_PTRSIZE LECIE..1: LSFDE..1: .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */ LASFDE..1: .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */ .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */ .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */ .byte 0 /* uleb128 0x0; Augmentation size */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..0-LFB..0 .byte 0x11 /* DW_CFA_def_offset_extended_sf */ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ .byte 0x9f /* DW_CFA_offset Register r31 */ .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */ .byte 0x9e /* DW_CFA_offset Register r30 */ .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */ .byte 0x9d /* DW_CFA_offset Register r29 */ .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */ .byte 0x9c /* DW_CFA_offset Register r28 */ .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..1-LCFI..0 .byte 0xd /* DW_CFA_def_cfa_register */ .byte 0x1c /* uleb128 28; Register r28 */ .align LOG2_PTRSIZE LEFDE..1: LSFDE..2: .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */ LASFDE..2: .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */ .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */ .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */ .byte 0 /* uleb128 0x0; Augmentation size */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..2-LFB..1 .byte 0x11 /* DW_CFA_def_offset_extended_sf */ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ .byte 0x9f /* DW_CFA_offset Register r31 */ .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */ .byte 0x9e /* DW_CFA_offset Register r30 */ .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */ .byte 0x9d /* DW_CFA_offset Register r29 */ .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */ .byte 0x9c /* DW_CFA_offset Register r28 */ .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..3-LCFI..2 .byte 0xd /* DW_CFA_def_cfa_register */ .byte 0x1c /* uleb128 28; Register r28 */ .align LOG2_PTRSIZE LEFDE..2: .vbyte 4,0 /* End of FDEs */ .csect .text[PR] .ref _GLOBAL__F_libffi_src_powerpc_aix /* Prevents garbage collection by AIX linker */ ====================File: src/powerpc/aix_closure.S==================== /* ----------------------------------------------------------------------- aix_closure.S - Copyright (c) 2002, 2003, 2009 Free Software Foundation, Inc. based on darwin_closure.S PowerPC Assembly glue. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ .set r0,0 .set r1,1 .set r2,2 .set r3,3 .set r4,4 .set r5,5 .set r6,6 .set r7,7 .set r8,8 .set r9,9 .set r10,10 .set r11,11 .set r12,12 .set r13,13 .set r14,14 .set r15,15 .set r16,16 .set r17,17 .set r18,18 .set r19,19 .set r20,20 .set r21,21 .set r22,22 .set r23,23 .set r24,24 .set r25,25 .set r26,26 .set r27,27 .set r28,28 .set r29,29 .set r30,30 .set r31,31 .set f0,0 .set f1,1 .set f2,2 .set f3,3 .set f4,4 .set f5,5 .set f6,6 .set f7,7 .set f8,8 .set f9,9 .set f10,10 .set f11,11 .set f12,12 .set f13,13 .set f14,14 .set f15,15 .set f16,16 .set f17,17 .set f18,18 .set f19,19 .set f20,20 .set f21,21 .extern .ffi_closure_helper_DARWIN .extern .ffi_go_closure_helper_DARWIN #define LIBFFI_ASM #define JUMPTARGET(name) name #define L(x) x .file "aix_closure.S" .toc LC..60: .tc L..60[TC],L..60 .csect .text[PR] .align 2 .csect .text[PR] .align 2 .globl ffi_closure_ASM .globl .ffi_closure_ASM .csect ffi_closure_ASM[DS] ffi_closure_ASM: #ifdef __64BIT__ .llong .ffi_closure_ASM, TOC[tc0], 0 .csect .text[PR] .ffi_closure_ASM: .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0 .bf __LINE__ .line 1 LFB..0: /* we want to build up an area for the parameters passed */ /* in registers (both floating point and integer) */ /* we store gpr 3 to gpr 10 (aligned to 4) in the parents outgoing area */ std r3, 48+(0*8)(r1) std r4, 48+(1*8)(r1) std r5, 48+(2*8)(r1) std r6, 48+(3*8)(r1) mflr r0 std r7, 48+(4*8)(r1) std r8, 48+(5*8)(r1) std r9, 48+(6*8)(r1) std r10, 48+(7*8)(r1) std r0, 16(r1) /* save the return address */ LCFI..0: /* 48 Bytes (Linkage Area) */ /* 64 Bytes (params) */ /* 16 Bytes (result) */ /* 104 Bytes (13*8 from FPR) */ /* 8 Bytes (alignment) */ /* 240 Bytes */ stdu r1, -240(r1) /* skip over caller save area keep stack aligned to 16 */ LCFI..1: /* next save fpr 1 to fpr 13 (aligned to 8) */ stfd f1, 128+(0*8)(r1) stfd f2, 128+(1*8)(r1) stfd f3, 128+(2*8)(r1) stfd f4, 128+(3*8)(r1) stfd f5, 128+(4*8)(r1) stfd f6, 128+(5*8)(r1) stfd f7, 128+(6*8)(r1) stfd f8, 128+(7*8)(r1) stfd f9, 128+(8*8)(r1) stfd f10, 128+(9*8)(r1) stfd f11, 128+(10*8)(r1) stfd f12, 128+(11*8)(r1) stfd f13, 128+(12*8)(r1) /* set up registers for the routine that actually does the work */ /* get the context pointer from the trampoline */ mr r3, r11 /* now load up the pointer to the result storage */ addi r4, r1, 112 /* now load up the pointer to the saved gpr registers */ addi r5, r1, 288 /* now load up the pointer to the saved fpr registers */ addi r6, r1, 128 /* make the call */ bl .ffi_closure_helper_DARWIN nop .Ldoneclosure: /* now r3 contains the return type */ /* so use it to look up in a table */ /* so we know how to deal with each type */ /* look up the proper starting point in table */ /* by using return type as offset */ lhz r3, 10(r3) /* load type from return type */ ld r4, LC..60(2) /* get address of jump table */ sldi r3, r3, 4 /* now multiply return type by 16 */ ld r0, 240+16(r1) /* load return address */ add r3, r3, r4 /* add contents of table to table address */ mtctr r3 bctr /* jump to it */ /* Each fragment must be exactly 16 bytes long (4 instructions). Align to 16 byte boundary for cache and dispatch efficiency. */ .align 4 L..60: /* case FFI_TYPE_VOID */ mtlr r0 addi r1, r1, 240 blr nop /* case FFI_TYPE_INT */ lwa r3, 112+4(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_FLOAT */ lfs f1, 112+0(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_DOUBLE */ lfd f1, 112+0(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_LONGDOUBLE */ lfd f1, 112+0(r1) mtlr r0 lfd f2, 112+8(r1) b L..finish /* case FFI_TYPE_UINT8 */ lbz r3, 112+7(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_SINT8 */ lbz r3, 112+7(r1) mtlr r0 extsb r3, r3 b L..finish /* case FFI_TYPE_UINT16 */ lhz r3, 112+6(r1) mtlr r0 L..finish: addi r1, r1, 240 blr /* case FFI_TYPE_SINT16 */ lha r3, 112+6(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_UINT32 */ lwz r3, 112+4(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_SINT32 */ lwa r3, 112+4(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_UINT64 */ ld r3, 112+0(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_SINT64 */ ld r3, 112+0(r1) mtlr r0 addi r1, r1, 240 blr /* case FFI_TYPE_STRUCT */ mtlr r0 addi r1, r1, 240 blr nop /* case FFI_TYPE_POINTER */ ld r3, 112+0(r1) mtlr r0 addi r1, r1, 240 blr LFE..0: #else /* ! __64BIT__ */ .long .ffi_closure_ASM, TOC[tc0], 0 .csect .text[PR] .ffi_closure_ASM: .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0 .bf __LINE__ .line 1 LFB..0: /* we want to build up an area for the parameters passed */ /* in registers (both floating point and integer) */ /* we store gpr 3 to gpr 10 (aligned to 4) in the parents outgoing area */ stw r3, 24+(0*4)(r1) stw r4, 24+(1*4)(r1) stw r5, 24+(2*4)(r1) stw r6, 24+(3*4)(r1) mflr r0 stw r7, 24+(4*4)(r1) stw r8, 24+(5*4)(r1) stw r9, 24+(6*4)(r1) stw r10, 24+(7*4)(r1) stw r0, 8(r1) LCFI..0: /* 24 Bytes (Linkage Area) */ /* 32 Bytes (params) */ /* 16 Bytes (result) */ /* 104 Bytes (13*8 from FPR) */ /* 176 Bytes */ stwu r1, -176(r1) /* skip over caller save area keep stack aligned to 16 */ LCFI..1: /* next save fpr 1 to fpr 13 (aligned to 8) */ stfd f1, 72+(0*8)(r1) stfd f2, 72+(1*8)(r1) stfd f3, 72+(2*8)(r1) stfd f4, 72+(3*8)(r1) stfd f5, 72+(4*8)(r1) stfd f6, 72+(5*8)(r1) stfd f7, 72+(6*8)(r1) stfd f8, 72+(7*8)(r1) stfd f9, 72+(8*8)(r1) stfd f10, 72+(9*8)(r1) stfd f11, 72+(10*8)(r1) stfd f12, 72+(11*8)(r1) stfd f13, 72+(12*8)(r1) /* set up registers for the routine that actually does the work */ /* get the context pointer from the trampoline */ mr r3, r11 /* now load up the pointer to the result storage */ addi r4, r1, 56 /* now load up the pointer to the saved gpr registers */ addi r5, r1, 200 /* now load up the pointer to the saved fpr registers */ addi r6, r1, 72 /* make the call */ bl .ffi_closure_helper_DARWIN nop .Ldoneclosure: /* now r3 contains the return type */ /* so use it to look up in a table */ /* so we know how to deal with each type */ /* look up the proper starting point in table */ /* by using return type as offset */ lhz r3, 6(r3) /* load type from return type */ lwz r4, LC..60(2) /* get address of jump table */ slwi r3, r3, 4 /* now multiply return type by 16 */ lwz r0, 176+8(r1) /* load return address */ add r3, r3, r4 /* add contents of table to table address */ mtctr r3 bctr /* jump to it */ /* Each fragment must be exactly 16 bytes long (4 instructions). Align to 16 byte boundary for cache and dispatch efficiency. */ .align 4 L..60: /* case FFI_TYPE_VOID */ mtlr r0 addi r1, r1, 176 blr nop /* case FFI_TYPE_INT */ lwz r3, 56+0(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_FLOAT */ lfs f1, 56+0(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_DOUBLE */ lfd f1, 56+0(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_LONGDOUBLE */ lfd f1, 56+0(r1) mtlr r0 lfd f2, 56+8(r1) b L..finish /* case FFI_TYPE_UINT8 */ lbz r3, 56+3(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_SINT8 */ lbz r3, 56+3(r1) mtlr r0 extsb r3, r3 b L..finish /* case FFI_TYPE_UINT16 */ lhz r3, 56+2(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_SINT16 */ lha r3, 56+2(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_UINT32 */ lwz r3, 56+0(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_SINT32 */ lwz r3, 56+0(r1) mtlr r0 addi r1, r1, 176 blr /* case FFI_TYPE_UINT64 */ lwz r3, 56+0(r1) mtlr r0 lwz r4, 56+4(r1) b L..finish /* case FFI_TYPE_SINT64 */ lwz r3, 56+0(r1) mtlr r0 lwz r4, 56+4(r1) b L..finish /* case FFI_TYPE_STRUCT */ mtlr r0 addi r1, r1, 176 blr nop /* case FFI_TYPE_POINTER */ lwz r3, 56+0(r1) mtlr r0 L..finish: addi r1, r1, 176 blr LFE..0: #endif .ef __LINE__ /* END(ffi_closure_ASM) */ .csect .text[PR] .align 2 .globl ffi_go_closure_ASM .globl .ffi_go_closure_ASM .csect ffi_go_closure_ASM[DS] ffi_go_closure_ASM: #ifdef __64BIT__ .llong .ffi_go_closure_ASM, TOC[tc0], 0 .csect .text[PR] .ffi_go_closure_ASM: .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1 .bf __LINE__ .line 1 LFB..1: /* we want to build up an area for the parameters passed */ /* in registers (both floating point and integer) */ /* we store gpr 3 to gpr 10 (aligned to 4) in the parents outgoing area */ std r3, 48+(0*8)(r1) std r4, 48+(1*8)(r1) std r5, 48+(2*8)(r1) std r6, 48+(3*8)(r1) mflr r0 std r7, 48+(4*8)(r1) std r8, 48+(5*8)(r1) std r9, 48+(6*8)(r1) std r10, 48+(7*8)(r1) std r0, 16(r1) /* save the return address */ LCFI..2: /* 48 Bytes (Linkage Area) */ /* 64 Bytes (params) */ /* 16 Bytes (result) */ /* 104 Bytes (13*8 from FPR) */ /* 8 Bytes (alignment) */ /* 240 Bytes */ stdu r1, -240(r1) /* skip over caller save area keep stack aligned to 16 */ LCFI..3: /* next save fpr 1 to fpr 13 (aligned to 8) */ stfd f1, 128+(0*8)(r1) stfd f2, 128+(1*8)(r1) stfd f3, 128+(2*8)(r1) stfd f4, 128+(3*8)(r1) stfd f5, 128+(4*8)(r1) stfd f6, 128+(5*8)(r1) stfd f7, 128+(6*8)(r1) stfd f8, 128+(7*8)(r1) stfd f9, 128+(8*8)(r1) stfd f10, 128+(9*8)(r1) stfd f11, 128+(10*8)(r1) stfd f12, 128+(11*8)(r1) stfd f13, 128+(12*8)(r1) /* set up registers for the routine that actually does the work */ mr r3, r11 /* go closure */ /* now load up the pointer to the result storage */ addi r4, r1, 112 /* now load up the pointer to the saved gpr registers */ addi r5, r1, 288 /* now load up the pointer to the saved fpr registers */ addi r6, r1, 128 /* make the call */ bl .ffi_go_closure_helper_DARWIN nop b .Ldoneclosure LFE..1: #else /* ! __64BIT__ */ .long .ffi_go_closure_ASM, TOC[tc0], 0 .csect .text[PR] .ffi_go_closure_ASM: .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1 .bf __LINE__ .line 1 LFB..1: /* we want to build up an area for the parameters passed */ /* in registers (both floating point and integer) */ /* we store gpr 3 to gpr 10 (aligned to 4) in the parents outgoing area */ stw r3, 24+(0*4)(r1) stw r4, 24+(1*4)(r1) stw r5, 24+(2*4)(r1) stw r6, 24+(3*4)(r1) mflr r0 stw r7, 24+(4*4)(r1) stw r8, 24+(5*4)(r1) stw r9, 24+(6*4)(r1) stw r10, 24+(7*4)(r1) stw r0, 8(r1) LCFI..2: /* 24 Bytes (Linkage Area) */ /* 32 Bytes (params) */ /* 16 Bytes (result) */ /* 104 Bytes (13*8 from FPR) */ /* 176 Bytes */ stwu r1, -176(r1) /* skip over caller save area keep stack aligned to 16 */ LCFI..3: /* next save fpr 1 to fpr 13 (aligned to 8) */ stfd f1, 72+(0*8)(r1) stfd f2, 72+(1*8)(r1) stfd f3, 72+(2*8)(r1) stfd f4, 72+(3*8)(r1) stfd f5, 72+(4*8)(r1) stfd f6, 72+(5*8)(r1) stfd f7, 72+(6*8)(r1) stfd f8, 72+(7*8)(r1) stfd f9, 72+(8*8)(r1) stfd f10, 72+(9*8)(r1) stfd f11, 72+(10*8)(r1) stfd f12, 72+(11*8)(r1) stfd f13, 72+(12*8)(r1) /* set up registers for the routine that actually does the work */ mr r3, 11 /* go closure */ /* now load up the pointer to the result storage */ addi r4, r1, 56 /* now load up the pointer to the saved gpr registers */ addi r5, r1, 200 /* now load up the pointer to the saved fpr registers */ addi r6, r1, 72 /* make the call */ bl .ffi_go_closure_helper_DARWIN nop b .Ldoneclosure LFE..1: #endif .ef __LINE__ /* END(ffi_go_closure_ASM) */ /* EH frame stuff. */ #define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */ #ifdef __64BIT__ #define PTRSIZE 8 #define LOG2_PTRSIZE 3 #define CFA_OFFSET 0xf0,0x01 /* LEB128 240 */ #define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */ #define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */ #else #define PTRSIZE 4 #define LOG2_PTRSIZE 2 #define CFA_OFFSET 0xb0,0x01 /* LEB128 176 */ #define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */ #define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */ #endif .csect _unwind.ro_[RO],4 .align LOG2_PTRSIZE .globl _GLOBAL__F_libffi_src_powerpc_aix_closure _GLOBAL__F_libffi_src_powerpc_aix_closure: Lframe..1: .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */ LSCIE..1: .vbyte 4,0 /* CIE Identifier Tag */ .byte 0x3 /* CIE Version */ .byte "zR" /* CIE Augmentation */ .byte 0 .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */ .byte LR_REGNO /* CIE RA Column */ .byte 0x1 /* uleb128 0x1; Augmentation size */ .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */ .byte 0xc /* DW_CFA_def_cfa */ .byte 0x1 /* uleb128 0x1; Register r1 */ .byte 0 /* uleb128 0x0; Offset 0 */ .align LOG2_PTRSIZE LECIE..1: LSFDE..1: .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */ LASFDE..1: .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */ .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */ .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */ .byte 0 /* uleb128 0x0; Augmentation size */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..1-LCFI..0 .byte 0xe /* DW_CFA_def_cfa_offset */ .byte CFA_OFFSET /* uleb128 176/240 */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..0-LFB..0 .byte 0x11 /* DW_CFA_offset_extended_sf */ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ .align LOG2_PTRSIZE LEFDE..1: LSFDE..2: .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */ LASFDE..2: .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */ .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */ .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */ .byte 0 /* uleb128 0x0; Augmentation size */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..3-LCFI..2 .byte 0xe /* DW_CFA_def_cfa_offset */ .byte CFA_OFFSET /* uleb128 176/240 */ .byte 0x4 /* DW_CFA_advance_loc4 */ .vbyte 4,LCFI..2-LFB..1 .byte 0x11 /* DW_CFA_offset_extended_sf */ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ .align LOG2_PTRSIZE LEFDE..2: .vbyte 4,0 /* End of FDEs */ .csect .text[PR] .ref _GLOBAL__F_libffi_src_powerpc_aix_closure /* Prevents garbage collection by AIX linker */ ====================File: src/powerpc/asm.h==================== /* ----------------------------------------------------------------------- asm.h - Copyright (c) 1998 Geoffrey Keating PowerPC Assembly glue. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #define ASM_GLOBAL_DIRECTIVE .globl #define C_SYMBOL_NAME(name) name /* Macro for a label. */ #ifdef __STDC__ #define C_LABEL(name) name##: #else #define C_LABEL(name) name/**/: #endif /* This seems to always be the case on PPC. */ #define ALIGNARG(log2) log2 /* For ELF we need the `.type' directive to make shared libs work right. */ #define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; #define ASM_SIZE_DIRECTIVE(name) .size name,.-name /* If compiled for profiling, call `_mcount' at the start of each function. */ #ifdef PROF /* The mcount code relies on the return address being on the stack to locate our caller and so it can restore it; so store one just for its benefit. */ #ifdef PIC #define CALL_MCOUNT \ .pushsection; \ .section ".data"; \ .align ALIGNARG(2); \ 0:.long 0; \ .previous; \ mflr %r0; \ stw %r0,4(%r1); \ bl _GLOBAL_OFFSET_TABLE_@local-4; \ mflr %r11; \ lwz %r0,0b@got(%r11); \ bl JUMPTARGET(_mcount); #else /* PIC */ #define CALL_MCOUNT \ .section ".data"; \ .align ALIGNARG(2); \ 0:.long 0; \ .previous; \ mflr %r0; \ lis %r11,0b@ha; \ stw %r0,4(%r1); \ addi %r0,%r11,0b@l; \ bl JUMPTARGET(_mcount); #endif /* PIC */ #else /* PROF */ #define CALL_MCOUNT /* Do nothing. */ #endif /* PROF */ #define ENTRY(name) \ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ .align ALIGNARG(2); \ C_LABEL(name) \ CALL_MCOUNT #define EALIGN_W_0 /* No words to insert. */ #define EALIGN_W_1 nop #define EALIGN_W_2 nop;nop #define EALIGN_W_3 nop;nop;nop #define EALIGN_W_4 EALIGN_W_3;nop #define EALIGN_W_5 EALIGN_W_4;nop #define EALIGN_W_6 EALIGN_W_5;nop #define EALIGN_W_7 EALIGN_W_6;nop /* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes past a 2^align boundary. */ #ifdef PROF #define EFFI_ALIGN(name, alignt, words) \ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ .align ALIGNARG(2); \ C_LABEL(name) \ CALL_MCOUNT \ b 0f; \ .align ALIGNARG(alignt); \ EALIGN_W_##words; \ 0: #else /* PROF */ #define EFFI_ALIGN(name, alignt, words) \ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ .align ALIGNARG(alignt); \ EALIGN_W_##words; \ C_LABEL(name) #endif #define END(name) \ ASM_SIZE_DIRECTIVE(name) #ifdef PIC #define JUMPTARGET(name) name##@plt #else #define JUMPTARGET(name) name #endif /* Local labels stripped out by the linker. */ #define L(x) .L##x ====================File: src/powerpc/darwin.S==================== /* ----------------------------------------------------------------------- darwin.S - Copyright (c) 2000 John Hornkvist Copyright (c) 2004, 2010 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 #if defined(__ppc64__) #define MODE_CHOICE(x, y) y #else #define MODE_CHOICE(x, y) x #endif #define machine_choice MODE_CHOICE(ppc7400,ppc64) ; Define some pseudo-opcodes for size-independent load & store of GPRs ... #define lgu MODE_CHOICE(lwzu, ldu) #define lg MODE_CHOICE(lwz,ld) #define sg MODE_CHOICE(stw,std) #define sgu MODE_CHOICE(stwu,stdu) #define sgux MODE_CHOICE(stwux,stdux) ; ... and the size of GPRs and their storage indicator. #define GPR_BYTES MODE_CHOICE(4,8) #define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ #define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ ; From the ABI doc: "Mac OS X ABI Function Call Guide" Version 2009-02-04. #define LINKAGE_SIZE MODE_CHOICE(24,48) #define PARAM_AREA MODE_CHOICE(32,64) #define SAVED_LR_OFFSET MODE_CHOICE(8,16) /* save position for lr */ /* If there is any FP stuff we make space for all of the regs. */ #define SAVED_FPR_COUNT 13 #define FPR_SIZE 8 #define RESULT_BYTES 16 /* This should be kept in step with the same value in ffi_darwin.c. */ #define ASM_NEEDS_REGISTERS 4 #define SAVE_REGS_SIZE (ASM_NEEDS_REGISTERS * GPR_BYTES) #include #include #define JUMPTARGET(name) name #define L(x) x .text .align 2 .globl _ffi_prep_args .align 2 .globl _ffi_call_DARWIN /* We arrive here with: r3 = ptr to extended cif. r4 = -bytes. r5 = cif flags. r6 = ptr to return value. r7 = fn pointer (user func). r8 = fn pointer (ffi_prep_args). r9 = ffi_type* for the ret val. */ _ffi_call_DARWIN: Lstartcode: mr r12,r8 /* We only need r12 until the call, so it does not have to be saved. */ LFB1: /* Save the old stack pointer as AP. */ mr r8,r1 LCFI0: /* Save the retval type in parents frame. */ sg r9,(LINKAGE_SIZE+6*GPR_BYTES)(r8) /* Allocate the stack space we need. */ sgux r1,r1,r4 /* Save registers we use. */ mflr r9 sg r9,SAVED_LR_OFFSET(r8) sg r28,-(4 * GPR_BYTES)(r8) sg r29,-(3 * GPR_BYTES)(r8) sg r30,-(2 * GPR_BYTES)(r8) sg r31,-( GPR_BYTES)(r8) #if !defined(POWERPC_DARWIN) /* The TOC slot is reserved in the Darwin ABI and r2 is volatile. */ sg r2,(5 * GPR_BYTES)(r1) #endif LCFI1: /* Save arguments over call. */ mr r31,r5 /* flags, */ mr r30,r6 /* rvalue, */ mr r29,r7 /* function address, */ mr r28,r8 /* our AP. */ LCFI2: /* Call ffi_prep_args. r3 = extended cif, r4 = stack ptr copy. */ mr r4,r1 li r9,0 mtctr r12 /* r12 holds address of _ffi_prep_args. */ bctrl #if !defined(POWERPC_DARWIN) /* The TOC slot is reserved in the Darwin ABI and r2 is volatile. */ lg r2,(5 * GPR_BYTES)(r1) #endif /* Now do the call. Set up cr1 with bits 4-7 of the flags. */ mtcrf 0x40,r31 /* Get the address to call into CTR. */ mtctr r29 /* Load all those argument registers. We have set up a nice stack frame, just load it into registers. */ lg r3, (LINKAGE_SIZE )(r1) lg r4, (LINKAGE_SIZE + GPR_BYTES)(r1) lg r5, (LINKAGE_SIZE + 2 * GPR_BYTES)(r1) lg r6, (LINKAGE_SIZE + 3 * GPR_BYTES)(r1) nop lg r7, (LINKAGE_SIZE + 4 * GPR_BYTES)(r1) lg r8, (LINKAGE_SIZE + 5 * GPR_BYTES)(r1) lg r9, (LINKAGE_SIZE + 6 * GPR_BYTES)(r1) lg r10,(LINKAGE_SIZE + 7 * GPR_BYTES)(r1) L1: /* ... Load all the FP registers. */ bf 6,L2 /* No floats to load. */ lfd f1, -SAVE_REGS_SIZE-(13*FPR_SIZE)(r28) lfd f2, -SAVE_REGS_SIZE-(12*FPR_SIZE)(r28) lfd f3, -SAVE_REGS_SIZE-(11*FPR_SIZE)(r28) lfd f4, -SAVE_REGS_SIZE-(10*FPR_SIZE)(r28) nop lfd f5, -SAVE_REGS_SIZE-( 9*FPR_SIZE)(r28) lfd f6, -SAVE_REGS_SIZE-( 8*FPR_SIZE)(r28) lfd f7, -SAVE_REGS_SIZE-( 7*FPR_SIZE)(r28) lfd f8, -SAVE_REGS_SIZE-( 6*FPR_SIZE)(r28) nop lfd f9, -SAVE_REGS_SIZE-( 5*FPR_SIZE)(r28) lfd f10,-SAVE_REGS_SIZE-( 4*FPR_SIZE)(r28) lfd f11,-SAVE_REGS_SIZE-( 3*FPR_SIZE)(r28) lfd f12,-SAVE_REGS_SIZE-( 2*FPR_SIZE)(r28) nop lfd f13,-SAVE_REGS_SIZE-( 1*FPR_SIZE)(r28) L2: mr r12,r29 /* Put the target address in r12 as specified. */ mtctr r12 nop nop /* Make the call. */ bctrl /* Now, deal with the return value. */ /* m64 structure returns can occupy the same set of registers as would be used to pass such a structure as arg0 - so take care not to step on any possibly hot regs. */ /* Get the flags.. */ mtcrf 0x03,r31 ; we need c6 & cr7 now. ; FLAG_RETURNS_NOTHING also covers struct ret-by-ref. bt 30,L(done_return_value) ; FLAG_RETURNS_NOTHING bf 27,L(scalar_return_value) ; not FLAG_RETURNS_STRUCT /* OK, so we have a struct. */ #if defined(__ppc64__) bt 31,L(maybe_return_128) ; FLAG_RETURNS_128BITS, special case /* OK, we have to map the return back to a mem struct. We are about to trample the parents param area, so recover the return type. r29 is free, since the call is done. */ lg r29,(LINKAGE_SIZE + 6 * GPR_BYTES)(r28) sg r3, (LINKAGE_SIZE )(r28) sg r4, (LINKAGE_SIZE + GPR_BYTES)(r28) sg r5, (LINKAGE_SIZE + 2 * GPR_BYTES)(r28) sg r6, (LINKAGE_SIZE + 3 * GPR_BYTES)(r28) nop sg r7, (LINKAGE_SIZE + 4 * GPR_BYTES)(r28) sg r8, (LINKAGE_SIZE + 5 * GPR_BYTES)(r28) sg r9, (LINKAGE_SIZE + 6 * GPR_BYTES)(r28) sg r10,(LINKAGE_SIZE + 7 * GPR_BYTES)(r28) /* OK, so do the block move - we trust that memcpy will not trample the fprs... */ mr r3,r30 ; dest addi r4,r28,LINKAGE_SIZE ; source /* The size is a size_t, should be long. */ lg r5,0(r29) /* Figure out small structs */ cmpi 0,r5,4 bgt L3 ; 1, 2 and 4 bytes have special rules. cmpi 0,r5,3 beq L3 ; not 3 addi r4,r4,8 subf r4,r5,r4 L3: bl _memcpy /* ... do we need the FP registers? - recover the flags.. */ mtcrf 0x03,r31 ; we need c6 & cr7 now. bf 29,L(done_return_value) /* No floats in the struct. */ stfd f1, -SAVE_REGS_SIZE-(13*FPR_SIZE)(r28) stfd f2, -SAVE_REGS_SIZE-(12*FPR_SIZE)(r28) stfd f3, -SAVE_REGS_SIZE-(11*FPR_SIZE)(r28) stfd f4, -SAVE_REGS_SIZE-(10*FPR_SIZE)(r28) nop stfd f5, -SAVE_REGS_SIZE-( 9*FPR_SIZE)(r28) stfd f6, -SAVE_REGS_SIZE-( 8*FPR_SIZE)(r28) stfd f7, -SAVE_REGS_SIZE-( 7*FPR_SIZE)(r28) stfd f8, -SAVE_REGS_SIZE-( 6*FPR_SIZE)(r28) nop stfd f9, -SAVE_REGS_SIZE-( 5*FPR_SIZE)(r28) stfd f10,-SAVE_REGS_SIZE-( 4*FPR_SIZE)(r28) stfd f11,-SAVE_REGS_SIZE-( 3*FPR_SIZE)(r28) stfd f12,-SAVE_REGS_SIZE-( 2*FPR_SIZE)(r28) nop stfd f13,-SAVE_REGS_SIZE-( 1*FPR_SIZE)(r28) mr r3,r29 ; ffi_type * mr r4,r30 ; dest addi r5,r28,-SAVE_REGS_SIZE-(13*FPR_SIZE) ; fprs xor r6,r6,r6 sg r6,(LINKAGE_SIZE + 7 * GPR_BYTES)(r28) addi r6,r28,(LINKAGE_SIZE + 7 * GPR_BYTES) ; point to a zeroed counter. bl _darwin64_struct_floats_to_mem b L(done_return_value) #else stw r3,0(r30) ; m32 the only struct return in reg is 4 bytes. #endif b L(done_return_value) L(fp_return_value): /* Do we have long double to store? */ bf 31,L(fd_return_value) ; FLAG_RETURNS_128BITS stfd f1,0(r30) stfd f2,FPR_SIZE(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) L(scalar_return_value): bt 29,L(fp_return_value) ; FLAG_RETURNS_FP ; ffi_arg is defined as unsigned long. sg r3,0(r30) ; Save the reg. bf 28,L(done_return_value) ; not FLAG_RETURNS_64BITS #if defined(__ppc64__) L(maybe_return_128): std r3,0(r30) bf 31,L(done_return_value) ; not FLAG_RETURNS_128BITS std r4,8(r30) #else stw r4,4(r30) #endif /* Fall through. */ /* We want this at the end to simplify eh epilog computation. */ L(done_return_value): /* Restore the registers we used and return. */ lg r29,SAVED_LR_OFFSET(r28) ; epilog lg r31,-(1 * GPR_BYTES)(r28) mtlr r29 lg r30,-(2 * GPR_BYTES)(r28) lg r29,-(3 * GPR_BYTES)(r28) lg r28,-(4 * GPR_BYTES)(r28) lg r1,0(r1) blr LFE1: .align 1 /* END(_ffi_call_DARWIN) */ /* Provide a null definition of _ffi_call_AIX. */ .text .globl _ffi_call_AIX .align 2 _ffi_call_AIX: blr /* END(_ffi_call_AIX) */ /* EH stuff. */ #define EH_DATA_ALIGN_FACT MODE_CHOICE(0x7c,0x78) .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 EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor .byte 0x41 ; CIE RA Column .byte 0x1 ; uleb128 0x1; Augmentation size .byte 0x10 ; FDE Encoding (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 Lstartcode-. ; FDE initial location .set L$set$3,LFE1-Lstartcode .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-Lstartcode .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: .align 1 ====================File: src/powerpc/darwin_closure.S==================== /* ----------------------------------------------------------------------- darwin_closure.S - Copyright (c) 2002, 2003, 2004, 2010, Free Software Foundation, Inc. based on ppc_closure.S PowerPC Assembly glue. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #define LIBFFI_ASM #define L(x) x #if defined(__ppc64__) #define MODE_CHOICE(x, y) y #else #define MODE_CHOICE(x, y) x #endif #define machine_choice MODE_CHOICE(ppc7400,ppc64) ; Define some pseudo-opcodes for size-independent load & store of GPRs ... #define lgu MODE_CHOICE(lwzu, ldu) #define lg MODE_CHOICE(lwz,ld) #define sg MODE_CHOICE(stw,std) #define sgu MODE_CHOICE(stwu,stdu) ; ... and the size of GPRs and their storage indicator. #define GPR_BYTES MODE_CHOICE(4,8) #define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ #define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ ; From the ABI doc: "Mac OS X ABI Function Call Guide" Version 2009-02-04. #define LINKAGE_SIZE MODE_CHOICE(24,48) #define PARAM_AREA MODE_CHOICE(32,64) #define SAVED_CR_OFFSET MODE_CHOICE(4,8) /* save position for CR */ #define SAVED_LR_OFFSET MODE_CHOICE(8,16) /* save position for lr */ /* WARNING: if ffi_type is changed... here be monsters. Offsets of items within the result type. */ #define FFI_TYPE_TYPE MODE_CHOICE(6,10) #define FFI_TYPE_ELEM MODE_CHOICE(8,16) #define SAVED_FPR_COUNT 13 #define FPR_SIZE 8 /* biggest m64 struct ret is 8GPRS + 13FPRS = 168 bytes - rounded to 16bytes = 176. */ #define RESULT_BYTES MODE_CHOICE(16,176) ; The whole stack frame **MUST** be 16byte-aligned. #define SAVE_SIZE (((LINKAGE_SIZE+PARAM_AREA+SAVED_FPR_COUNT*FPR_SIZE+RESULT_BYTES)+15) & -16LL) #define PAD_SIZE (SAVE_SIZE-(LINKAGE_SIZE+PARAM_AREA+SAVED_FPR_COUNT*FPR_SIZE+RESULT_BYTES)) #define PARENT_PARM_BASE (SAVE_SIZE+LINKAGE_SIZE) #define FP_SAVE_BASE (LINKAGE_SIZE+PARAM_AREA) #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 ; We no longer need the pic symbol stub for Darwin >= 9. #define BLCLS_HELP _ffi_closure_helper_DARWIN #define STRUCT_RETVALUE_P _darwin64_struct_ret_by_value_p #define PASS_STR_FLOATS _darwin64_pass_struct_floats #undef WANT_STUB #else #define BLCLS_HELP L_ffi_closure_helper_DARWIN$stub #define STRUCT_RETVALUE_P L_darwin64_struct_ret_by_value_p$stub #define PASS_STR_FLOATS L_darwin64_pass_struct_floats$stub #define WANT_STUB #endif /* m32/m64 The stack layout looks like this: | Additional params... | | Higher address ~ ~ ~ | Parameters (at least 8*4/8=32/64) | | NUM_GPR_ARG_REGISTERS |--------------------------------------------| | | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | |--------------------------------------------| | | Reserved 2*4/8 | | |--------------------------------------------| | | Space for callee`s LR 4/8 | | |--------------------------------------------| | | Saved CR [low word for m64] 4/8 | | |--------------------------------------------| | | Current backchain pointer 4/8 |-/ Parent`s frame. |--------------------------------------------| <+ <<< on entry to | Result Bytes 16/176 | | |--------------------------------------------| | ~ padding to 16-byte alignment ~ ~ |--------------------------------------------| | | NUM_FPR_ARG_REGISTERS slots | | | here fp13 .. fp1 13*8 | | |--------------------------------------------| | | R3..R10 8*4/8=32/64 | | NUM_GPR_ARG_REGISTERS |--------------------------------------------| | | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | |--------------------------------------------| | stack | | Reserved [compiler,binder] 2*4/8 | | grows | |--------------------------------------------| | down V | Space for callees LR 4/8 | | |--------------------------------------------| | lower addresses | Saved CR [low word for m64] 4/8 | | |--------------------------------------------| | stack pointer here | Current backchain pointer 4/8 |-/ during |--------------------------------------------| <<< call. */ .file "darwin_closure.S" .machine machine_choice .text .globl _ffi_closure_ASM .align LOG2_GPR_BYTES _ffi_closure_ASM: LFB1: Lstartcode: mflr r0 /* extract return address */ sg r0,SAVED_LR_OFFSET(r1) /* save the return address */ LCFI0: sgu r1,-SAVE_SIZE(r1) /* skip over caller save area keep stack aligned to 16. */ LCFI1: /* We want to build up an area for the parameters passed in registers. (both floating point and integer) */ /* Put gpr 3 to gpr 10 in the parents outgoing area... ... the remainder of any params that overflowed the regs will follow here. */ sg r3, (PARENT_PARM_BASE )(r1) sg r4, (PARENT_PARM_BASE + GPR_BYTES )(r1) sg r5, (PARENT_PARM_BASE + GPR_BYTES * 2)(r1) sg r6, (PARENT_PARM_BASE + GPR_BYTES * 3)(r1) sg r7, (PARENT_PARM_BASE + GPR_BYTES * 4)(r1) sg r8, (PARENT_PARM_BASE + GPR_BYTES * 5)(r1) sg r9, (PARENT_PARM_BASE + GPR_BYTES * 6)(r1) sg r10,(PARENT_PARM_BASE + GPR_BYTES * 7)(r1) /* We save fpr 1 to fpr 14 in our own save frame. */ stfd f1, (FP_SAVE_BASE )(r1) stfd f2, (FP_SAVE_BASE + FPR_SIZE )(r1) stfd f3, (FP_SAVE_BASE + FPR_SIZE * 2 )(r1) stfd f4, (FP_SAVE_BASE + FPR_SIZE * 3 )(r1) stfd f5, (FP_SAVE_BASE + FPR_SIZE * 4 )(r1) stfd f6, (FP_SAVE_BASE + FPR_SIZE * 5 )(r1) stfd f7, (FP_SAVE_BASE + FPR_SIZE * 6 )(r1) stfd f8, (FP_SAVE_BASE + FPR_SIZE * 7 )(r1) stfd f9, (FP_SAVE_BASE + FPR_SIZE * 8 )(r1) stfd f10,(FP_SAVE_BASE + FPR_SIZE * 9 )(r1) stfd f11,(FP_SAVE_BASE + FPR_SIZE * 10)(r1) stfd f12,(FP_SAVE_BASE + FPR_SIZE * 11)(r1) stfd f13,(FP_SAVE_BASE + FPR_SIZE * 12)(r1) /* Set up registers for the routine that actually does the work get the context pointer from the trampoline. */ mr r3,r11 /* Now load up the pointer to the result storage. */ addi r4,r1,(SAVE_SIZE-RESULT_BYTES) /* Now load up the pointer to the saved gpr registers. */ addi r5,r1,PARENT_PARM_BASE /* Now load up the pointer to the saved fpr registers. */ addi r6,r1,FP_SAVE_BASE /* Make the call. */ bl BLCLS_HELP /* r3 contains the rtype pointer... save it since we will need it later. */ sg r3,LINKAGE_SIZE(r1) ; ffi_type * result_type lg r0,0(r3) ; size => r0 lhz r3,FFI_TYPE_TYPE(r3) ; type => r3 /* The helper will have intercepted structure returns and inserted the caller`s destination address for structs returned by ref. */ /* r3 contains the return type so use it to look up in a table so we know how to deal with each type. */ addi r5,r1,(SAVE_SIZE-RESULT_BYTES) /* Otherwise, our return is here. */ bl Lget_ret_type0_addr /* Get pointer to Lret_type0 into LR. */ mflr r4 /* Move to r4. */ slwi r3,r3,4 /* Now multiply return type by 16. */ add r3,r3,r4 /* Add contents of table to table address. */ mtctr r3 bctr /* Jump to it. */ LFE1: /* Each of the ret_typeX code fragments has to be exactly 16 bytes long (4 instructions). For cache effectiveness we align to a 16 byte boundary first. */ .align 4 nop nop nop Lget_ret_type0_addr: blrl /* case FFI_TYPE_VOID */ Lret_type0: b Lfinish nop nop nop /* case FFI_TYPE_INT */ Lret_type1: lg r3,0(r5) b Lfinish nop nop /* case FFI_TYPE_FLOAT */ Lret_type2: lfs f1,0(r5) b Lfinish nop nop /* case FFI_TYPE_DOUBLE */ Lret_type3: lfd f1,0(r5) b Lfinish nop nop /* case FFI_TYPE_LONGDOUBLE */ Lret_type4: lfd f1,0(r5) lfd f2,8(r5) b Lfinish nop /* case FFI_TYPE_UINT8 */ Lret_type5: #if defined(__ppc64__) lbz r3,7(r5) #else lbz r3,3(r5) #endif b Lfinish nop nop /* case FFI_TYPE_SINT8 */ Lret_type6: #if defined(__ppc64__) lbz r3,7(r5) #else lbz r3,3(r5) #endif extsb r3,r3 b Lfinish nop /* case FFI_TYPE_UINT16 */ Lret_type7: #if defined(__ppc64__) lhz r3,6(r5) #else lhz r3,2(r5) #endif b Lfinish nop nop /* case FFI_TYPE_SINT16 */ Lret_type8: #if defined(__ppc64__) lha r3,6(r5) #else lha r3,2(r5) #endif b Lfinish nop nop /* case FFI_TYPE_UINT32 */ Lret_type9: #if defined(__ppc64__) lwz r3,4(r5) #else lwz r3,0(r5) #endif b Lfinish nop nop /* case FFI_TYPE_SINT32 */ Lret_type10: #if defined(__ppc64__) lwz r3,4(r5) #else lwz r3,0(r5) #endif b Lfinish nop nop /* case FFI_TYPE_UINT64 */ Lret_type11: #if defined(__ppc64__) lg r3,0(r5) b Lfinish nop #else lwz r3,0(r5) lwz r4,4(r5) b Lfinish #endif nop /* case FFI_TYPE_SINT64 */ Lret_type12: #if defined(__ppc64__) lg r3,0(r5) b Lfinish nop #else lwz r3,0(r5) lwz r4,4(r5) b Lfinish #endif nop /* case FFI_TYPE_STRUCT */ Lret_type13: #if defined(__ppc64__) lg r3,0(r5) ; we need at least this... cmpi 0,r0,4 bgt Lstructend ; not a special small case b Lsmallstruct ; see if we need more. #else cmpwi 0,r0,4 bgt Lfinish ; not by value lg r3,0(r5) b Lfinish #endif /* case FFI_TYPE_POINTER */ Lret_type14: lg r3,0(r5) b Lfinish nop nop #if defined(__ppc64__) Lsmallstruct: beq Lfour ; continuation of Lret13. cmpi 0,r0,3 beq Lfinish ; don`t adjust this - can`t be any floats here... srdi r3,r3,48 cmpi 0,r0,2 beq Lfinish ; .. or here .. srdi r3,r3,8 b Lfinish ; .. or here. Lfour: lg r6,LINKAGE_SIZE(r1) ; get the result type lg r6,FFI_TYPE_ELEM(r6) ; elements array pointer lg r6,0(r6) ; first element lhz r0,FFI_TYPE_TYPE(r6) ; OK go the type cmpi 0,r0,2 ; FFI_TYPE_FLOAT bne Lfourint lfs f1,0(r5) ; just one float in the struct. b Lfinish Lfourint: srdi r3,r3,32 ; four bytes. b Lfinish Lstructend: lg r3,LINKAGE_SIZE(r1) ; get the result type bl STRUCT_RETVALUE_P cmpi 0,r3,0 beq Lfinish ; nope. /* Recover a pointer to the results. */ addi r11,r1,(SAVE_SIZE-RESULT_BYTES) lg r3,0(r11) ; we need at least this... lg r4,8(r11) cmpi 0,r0,16 beq Lfinish ; special case 16 bytes we don't consider floats. /* OK, frustratingly, the process of saving the struct to mem might have messed with the FPRs, so we have to re-load them :(. We`ll use our FPRs space again - calling: void darwin64_pass_struct_floats (ffi_type *s, char *src, unsigned *nfpr, double **fprs) We`ll temporarily pinch the first two slots of the param area for local vars used by the routine. */ xor r6,r6,r6 addi r5,r1,PARENT_PARM_BASE ; some space sg r6,0(r5) ; *nfpr zeroed. addi r6,r5,8 ; **fprs addi r3,r1,FP_SAVE_BASE ; pointer to FPRs space sg r3,0(r6) mr r4,r11 ; the struct is here... lg r3,LINKAGE_SIZE(r1) ; ffi_type * result_type. bl PASS_STR_FLOATS ; get struct floats into FPR save space. /* See if we used any floats */ lwz r0,(SAVE_SIZE-RESULT_BYTES)(r1) cmpi 0,r0,0 beq Lstructints ; nope. /* OK load `em up... */ lfd f1, (FP_SAVE_BASE )(r1) lfd f2, (FP_SAVE_BASE + FPR_SIZE )(r1) lfd f3, (FP_SAVE_BASE + FPR_SIZE * 2 )(r1) lfd f4, (FP_SAVE_BASE + FPR_SIZE * 3 )(r1) lfd f5, (FP_SAVE_BASE + FPR_SIZE * 4 )(r1) lfd f6, (FP_SAVE_BASE + FPR_SIZE * 5 )(r1) lfd f7, (FP_SAVE_BASE + FPR_SIZE * 6 )(r1) lfd f8, (FP_SAVE_BASE + FPR_SIZE * 7 )(r1) lfd f9, (FP_SAVE_BASE + FPR_SIZE * 8 )(r1) lfd f10,(FP_SAVE_BASE + FPR_SIZE * 9 )(r1) lfd f11,(FP_SAVE_BASE + FPR_SIZE * 10)(r1) lfd f12,(FP_SAVE_BASE + FPR_SIZE * 11)(r1) lfd f13,(FP_SAVE_BASE + FPR_SIZE * 12)(r1) /* point back at our saved struct. */ Lstructints: addi r11,r1,(SAVE_SIZE-RESULT_BYTES) lg r3,0(r11) ; we end up picking the lg r4,8(r11) ; first two again. lg r5,16(r11) lg r6,24(r11) lg r7,32(r11) lg r8,40(r11) lg r9,48(r11) lg r10,56(r11) #endif /* case done */ Lfinish: addi r1,r1,SAVE_SIZE /* Restore stack pointer. */ lg r0,SAVED_LR_OFFSET(r1) /* Get return address. */ mtlr r0 /* Reset link register. */ blr Lendcode: .align 1 /* END(ffi_closure_ASM) */ /* EH frame stuff. */ #define EH_DATA_ALIGN_FACT MODE_CHOICE(0x7c,0x78) /* 176, 400 */ #define EH_FRAME_OFFSETA MODE_CHOICE(176,0x90) #define EH_FRAME_OFFSETB MODE_CHOICE(1,3) .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 EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor .byte 0x41 ; CIE RA Column .byte 0x1 ; uleb128 0x1; Augmentation size .byte 0x10 ; FDE Encoding (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 Lstartcode-. ; FDE initial location .set L$set$2,LFE1-Lstartcode .g_long L$set$2 ; 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 EH_FRAME_OFFSETA,EH_FRAME_OFFSETB ; uleb128 176,1/190,3 .byte 0x4 ; DW_CFA_advance_loc4 .set L$set$4,LCFI0-Lstartcode .long L$set$4 .byte 0x11 ; DW_CFA_offset_extended_sf .byte 0x41 ; uleb128 0x41 .byte 0x7e ; sleb128 -2 .align LOG2_GPR_BYTES LEFDE1: .align 1 #ifdef WANT_STUB .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 .align 5 L_ffi_closure_helper_DARWIN$stub: .indirect_symbol _ffi_closure_helper_DARWIN mflr r0 bcl 20,31,"L1$spb" "L1$spb": mflr r11 addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb") mtlr r0 lwzu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb")(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 #if defined(__ppc64__) .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 .align 5 L_darwin64_struct_ret_by_value_p$stub: .indirect_symbol _darwin64_struct_ret_by_value_p mflr r0 bcl 20,31,"L2$spb" "L2$spb": mflr r11 addis r11,r11,ha16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb") mtlr r0 lwzu r12,lo16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb")(r11) mtctr r12 bctr .lazy_symbol_pointer L_darwin64_struct_ret_by_value_p$lazy_ptr: .indirect_symbol _darwin64_struct_ret_by_value_p .g_long dyld_stub_binding_helper .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 .align 5 L_darwin64_pass_struct_floats$stub: .indirect_symbol _darwin64_pass_struct_floats mflr r0 bcl 20,31,"L3$spb" "L3$spb": mflr r11 addis r11,r11,ha16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb") mtlr r0 lwzu r12,lo16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb")(r11) mtctr r12 bctr .lazy_symbol_pointer L_darwin64_pass_struct_floats$lazy_ptr: .indirect_symbol _darwin64_pass_struct_floats .g_long dyld_stub_binding_helper # endif #endif ====================File: src/powerpc/ffi.c==================== /* ----------------------------------------------------------------------- ffi.c - Copyright (C) 2013 IBM Copyright (C) 2011 Anthony Green Copyright (C) 2011 Kyle Moffett Copyright (C) 2008 Red Hat, Inc Copyright (C) 2007, 2008 Free Software Foundation, Inc Copyright (c) 1998 Geoffrey Keating PowerPC Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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 "ffi_powerpc.h" #if HAVE_LONG_DOUBLE_VARIANT /* Adjust ffi_type_longdouble. */ void FFI_HIDDEN ffi_prep_types (ffi_abi abi) { # if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE # ifdef POWERPC64 ffi_prep_types_linux64 (abi); # else ffi_prep_types_sysv (abi); # endif # endif } #endif /* Perform machine dependent cif processing */ ffi_status FFI_HIDDEN ffi_prep_cif_machdep (ffi_cif *cif) { #ifdef POWERPC64 return ffi_prep_cif_linux64 (cif); #else return ffi_prep_cif_sysv (cif); #endif } ffi_status FFI_HIDDEN ffi_prep_cif_machdep_var (ffi_cif *cif, unsigned int nfixedargs MAYBE_UNUSED, unsigned int ntotalargs MAYBE_UNUSED) { #ifdef POWERPC64 return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs); #else return ffi_prep_cif_sysv (cif); #endif } static void ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, void *closure) { /* The final SYSV ABI says that structures smaller or equal 8 bytes are returned in r3/r4. A draft ABI used by linux instead returns them in memory. We bounce-buffer SYSV small struct return values so that sysv.S can write r3 and r4 to memory without worrying about struct size. For ELFv2 ABI, use a bounce buffer for homogeneous structs too, for similar reasons. This bounce buffer must be aligned to 16 bytes for use with homogeneous structs of vectors (float128). */ float128 smst_buffer[8]; extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; ecif.rvalue = rvalue; if ((cif->flags & FLAG_RETURNS_SMST) != 0) ecif.rvalue = smst_buffer; /* Ensure that we have a valid struct return value. FIXME: Isn't this just papering over a user problem? */ else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT) ecif.rvalue = alloca (cif->rtype->size); #ifdef POWERPC64 ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure, -(long) cif->bytes); #else ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes); #endif /* Check for a bounce-buffered return value */ if (rvalue && ecif.rvalue == smst_buffer) { unsigned int rsize = cif->rtype->size; #ifndef __LITTLE_ENDIAN__ /* The SYSV ABI returns a structure of up to 4 bytes in size left-padded in r3. */ # ifndef POWERPC64 if (rsize <= 4) memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); else # endif /* The SYSV ABI returns a structure of up to 8 bytes in size left-padded in r3/r4, and the ELFv2 ABI similarly returns a structure of up to 8 bytes in size left-padded in r3. But note that a structure of a single float is not paddded. */ if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0) memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); else #endif memcpy (rvalue, smst_buffer, rsize); } } void ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) { ffi_call_int (cif, fn, rvalue, avalue, NULL); } void ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, void *closure) { ffi_call_int (cif, fn, rvalue, avalue, closure); } ffi_status ffi_prep_closure_loc (ffi_closure *closure, ffi_cif *cif, void (*fun) (ffi_cif *, void *, void **, void *), void *user_data, void *codeloc) { #ifdef POWERPC64 return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc); #else return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc); #endif } ffi_status ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, void (*fun) (ffi_cif *, void *, void **, void *)) { #ifdef POWERPC64 closure->tramp = ffi_go_closure_linux64; #else closure->tramp = ffi_go_closure_sysv; #endif closure->cif = cif; closure->fun = fun; return FFI_OK; } ====================File: src/powerpc/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ #if defined (POWERPC) && defined (__powerpc64__) /* linux64 */ #ifndef POWERPC64 #define POWERPC64 #endif #elif defined (POWERPC_DARWIN) && defined (__ppc64__) /* Darwin64 */ #ifndef POWERPC64 #define POWERPC64 #endif #ifndef POWERPC_DARWIN64 #define POWERPC_DARWIN64 #endif #elif defined (POWERPC_AIX) && defined (__64BIT__) /* AIX64 */ #ifndef POWERPC64 #define POWERPC64 #endif #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, #if defined (POWERPC_AIX) FFI_AIX, FFI_DARWIN, FFI_DEFAULT_ABI = FFI_AIX, FFI_LAST_ABI #elif defined (POWERPC_DARWIN) FFI_AIX, FFI_DARWIN, FFI_DEFAULT_ABI = FFI_DARWIN, FFI_LAST_ABI #else /* The FFI_COMPAT values are used by old code. Since libffi may be a shared library we have to support old values for backwards compatibility. */ FFI_COMPAT_SYSV, FFI_COMPAT_GCC_SYSV, FFI_COMPAT_LINUX64, FFI_COMPAT_LINUX, FFI_COMPAT_LINUX_SOFT_FLOAT, # if defined (POWERPC64) /* This bit, always set in new code, must not be set in any of the old FFI_COMPAT values that might be used for 64-bit linux. We only need worry about FFI_COMPAT_LINUX64, but to be safe avoid all old values. */ FFI_LINUX = 8, /* This and following bits can reuse FFI_COMPAT values. */ FFI_LINUX_STRUCT_ALIGN = 1, FFI_LINUX_LONG_DOUBLE_128 = 2, FFI_LINUX_LONG_DOUBLE_IEEE128 = 4, FFI_DEFAULT_ABI = (FFI_LINUX # ifdef __STRUCT_PARM_ALIGN__ | FFI_LINUX_STRUCT_ALIGN # endif # ifdef __LONG_DOUBLE_128__ | FFI_LINUX_LONG_DOUBLE_128 # ifdef __LONG_DOUBLE_IEEE128__ | FFI_LINUX_LONG_DOUBLE_IEEE128 # endif # endif ), FFI_LAST_ABI = 16 # else /* This bit, always set in new code, must not be set in any of the old FFI_COMPAT values that might be used for 32-bit linux/sysv/bsd. */ FFI_SYSV = 8, /* This and following bits can reuse FFI_COMPAT values. */ FFI_SYSV_SOFT_FLOAT = 1, FFI_SYSV_STRUCT_RET = 2, FFI_SYSV_IBM_LONG_DOUBLE = 4, FFI_SYSV_LONG_DOUBLE_128 = 16, FFI_DEFAULT_ABI = (FFI_SYSV # ifdef __NO_FPRS__ | FFI_SYSV_SOFT_FLOAT # endif # if (defined (__SVR4_STRUCT_RETURN) \ || defined (POWERPC_FREEBSD) && !defined (__AIX_STRUCT_RETURN)) | FFI_SYSV_STRUCT_RET # endif # if __LDBL_MANT_DIG__ == 106 | FFI_SYSV_IBM_LONG_DOUBLE # endif # ifdef __LONG_DOUBLE_128__ | FFI_SYSV_LONG_DOUBLE_128 # endif ), FFI_LAST_ABI = 32 # endif #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (POWERPC) || defined (POWERPC_FREEBSD) # define FFI_GO_CLOSURES 1 # define FFI_TARGET_SPECIFIC_VARIADIC 1 # define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs #endif #if defined (POWERPC_AIX) # define FFI_GO_CLOSURES 1 #endif /* ppc_closure.S and linux64_closure.S expect this. */ #define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER /* We define additional types below. If generic types are added that must be supported by powerpc libffi then it is likely that FFI_PPC_TYPE_LAST needs increasing *and* the jump tables in ppc_closure.S and linux64_closure.S be extended. */ #if !(FFI_TYPE_LAST == FFI_PPC_TYPE_LAST \ || (FFI_TYPE_LAST == FFI_TYPE_COMPLEX \ && !defined FFI_TARGET_HAS_COMPLEX_TYPE)) # error "You likely have a broken powerpc libffi" #endif /* Needed for soft-float long-double-128 support. */ #define FFI_TYPE_UINT128 (FFI_PPC_TYPE_LAST + 1) /* Needed for FFI_SYSV small structure returns. */ #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2) /* Used by ELFv2 for homogenous structure returns. */ #define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1) #define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2) #define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3) #define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4) #define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5) #if _CALL_ELF == 2 # define FFI_TRAMPOLINE_SIZE 32 #else # if defined(POWERPC64) || defined(POWERPC_AIX) # if defined(POWERPC_DARWIN64) # define FFI_TRAMPOLINE_SIZE 48 # else # define FFI_TRAMPOLINE_SIZE 24 # endif # else /* POWERPC || POWERPC_AIX */ # define FFI_TRAMPOLINE_SIZE 40 # endif #endif #ifndef LIBFFI_ASM #if defined(POWERPC_DARWIN) || defined(POWERPC_AIX) struct ffi_aix_trampoline_struct { void * code_pointer; /* Pointer to ffi_closure_ASM */ void * toc; /* TOC */ void * static_chain; /* Pointer to closure */ }; #endif #endif #endif ====================File: src/powerpc/ppc_closure.S==================== /* ----------------------------------------------------------------------- sysv.h - Copyright (c) 2003 Jakub Jelinek Copyright (c) 2008 Red Hat, 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 AUTHORS OR COPYRIGHT HOLDERS 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 #include #include .file "ppc_closure.S" #ifndef POWERPC64 FFI_HIDDEN(ffi_closure_SYSV) ENTRY(ffi_closure_SYSV) .cfi_startproc stwu %r1,-144(%r1) .cfi_def_cfa_offset 144 mflr %r0 stw %r0,148(%r1) .cfi_offset 65, 4 # we want to build up an areas for the parameters passed # in registers (both floating point and integer) # so first save gpr 3 to gpr 10 (aligned to 4) stw %r3, 16(%r1) stw %r4, 20(%r1) stw %r5, 24(%r1) # set up registers for the routine that does the work # closure->cif lwz %r3,FFI_TRAMPOLINE_SIZE(%r11) # closure->fun lwz %r4,FFI_TRAMPOLINE_SIZE+4(%r11) # closure->user_data lwz %r5,FFI_TRAMPOLINE_SIZE+8(%r11) .Ldoclosure: stw %r6, 28(%r1) stw %r7, 32(%r1) stw %r8, 36(%r1) stw %r9, 40(%r1) stw %r10,44(%r1) #ifndef __NO_FPRS__ # next save fpr 1 to fpr 8 (aligned to 8) stfd %f1, 48(%r1) stfd %f2, 56(%r1) stfd %f3, 64(%r1) stfd %f4, 72(%r1) stfd %f5, 80(%r1) stfd %f6, 88(%r1) stfd %f7, 96(%r1) stfd %f8, 104(%r1) #endif # pointer to the result storage addi %r6,%r1,112 # pointer to the saved gpr registers addi %r7,%r1,16 # pointer to the saved fpr registers addi %r8,%r1,48 # pointer to the outgoing parameter save area in the previous frame # i.e. the previous frame pointer + 8 addi %r9,%r1,152 # make the call bl ffi_closure_helper_SYSV@local .Lret: # now r3 contains the return type # so use it to look up in a table # so we know how to deal with each type # look up the proper starting point in table # by using return type as offset mflr %r4 # move address of .Lret to r4 slwi %r3,%r3,4 # now multiply return type by 16 addi %r4, %r4, .Lret_type0 - .Lret lwz %r0,148(%r1) add %r3,%r3,%r4 # add contents of table to table address mtctr %r3 bctr # jump to it # Each of the ret_typeX code fragments has to be exactly 16 bytes long # (4 instructions). For cache effectiveness we align to a 16 byte boundary # first. .align 4 # case FFI_TYPE_VOID .Lret_type0: mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 nop # case FFI_TYPE_INT lwz %r3,112+0(%r1) mtlr %r0 .Lfinish: addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_FLOAT #ifndef __NO_FPRS__ lfs %f1,112+0(%r1) #else nop #endif mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_DOUBLE #ifndef __NO_FPRS__ lfd %f1,112+0(%r1) #else nop #endif mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_LONGDOUBLE #ifndef __NO_FPRS__ lfd %f1,112+0(%r1) lfd %f2,112+8(%r1) mtlr %r0 b .Lfinish #else mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 nop #endif # case FFI_TYPE_UINT8 #ifdef __LITTLE_ENDIAN__ lbz %r3,112+0(%r1) #else lbz %r3,112+3(%r1) #endif mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_SINT8 #ifdef __LITTLE_ENDIAN__ lbz %r3,112+0(%r1) #else lbz %r3,112+3(%r1) #endif extsb %r3,%r3 mtlr %r0 b .Lfinish # case FFI_TYPE_UINT16 #ifdef __LITTLE_ENDIAN__ lhz %r3,112+0(%r1) #else lhz %r3,112+2(%r1) #endif mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_SINT16 #ifdef __LITTLE_ENDIAN__ lha %r3,112+0(%r1) #else lha %r3,112+2(%r1) #endif mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_UINT32 lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_SINT32 lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_UINT64 lwz %r3,112+0(%r1) lwz %r4,112+4(%r1) mtlr %r0 b .Lfinish # case FFI_TYPE_SINT64 lwz %r3,112+0(%r1) lwz %r4,112+4(%r1) mtlr %r0 b .Lfinish # case FFI_TYPE_STRUCT mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 nop # case FFI_TYPE_POINTER lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_TYPE_UINT128 lwz %r3,112+0(%r1) lwz %r4,112+4(%r1) lwz %r5,112+8(%r1) b .Luint128 # The return types below are only used when the ABI type is FFI_SYSV. # case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct. lbz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct. lhz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. lwz %r3,112+0(%r1) #ifdef __LITTLE_ENDIAN__ mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 #else srwi %r3,%r3,8 mtlr %r0 b .Lfinish #endif # case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct. lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 # case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. lwz %r3,112+0(%r1) lwz %r4,112+4(%r1) #ifdef __LITTLE_ENDIAN__ mtlr %r0 b .Lfinish #else li %r5,24 b .Lstruct567 #endif # case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct. lwz %r3,112+0(%r1) lwz %r4,112+4(%r1) #ifdef __LITTLE_ENDIAN__ mtlr %r0 b .Lfinish #else li %r5,16 b .Lstruct567 #endif # case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct. lwz %r3,112+0(%r1) lwz %r4,112+4(%r1) #ifdef __LITTLE_ENDIAN__ mtlr %r0 b .Lfinish #else li %r5,8 b .Lstruct567 #endif # case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct. lwz %r3,112+0(%r1) lwz %r4,112+4(%r1) mtlr %r0 b .Lfinish #ifndef __LITTLE_ENDIAN__ .Lstruct567: subfic %r6,%r5,32 srw %r4,%r4,%r5 slw %r6,%r3,%r6 srw %r3,%r3,%r5 or %r4,%r6,%r4 mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_def_cfa_offset 144 #endif .Luint128: lwz %r6,112+12(%r1) mtlr %r0 addi %r1,%r1,144 .cfi_def_cfa_offset 0 blr .cfi_endproc END(ffi_closure_SYSV) FFI_HIDDEN(ffi_go_closure_sysv) ENTRY(ffi_go_closure_sysv) .cfi_startproc stwu %r1,-144(%r1) .cfi_def_cfa_offset 144 mflr %r0 stw %r0,148(%r1) .cfi_offset 65, 4 stw %r3, 16(%r1) stw %r4, 20(%r1) stw %r5, 24(%r1) # closure->cif lwz %r3,4(%r11) # closure->fun lwz %r4,8(%r11) # user_data mr %r5,%r11 b .Ldoclosure .cfi_endproc END(ffi_go_closure_sysv) #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif #endif ====================File: src/powerpc/sysv.S==================== /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 1998 Geoffrey Keating Copyright (C) 2007 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 AUTHORS OR COPYRIGHT HOLDERS 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 #include #include #ifndef POWERPC64 FFI_HIDDEN(ffi_call_SYSV) ENTRY(ffi_call_SYSV) .cfi_startproc /* Save the old stack pointer as AP. */ mr %r10,%r1 .cfi_def_cfa_register 10 /* Allocate the stack space we need. */ stwux %r1,%r1,%r8 /* Save registers we use. */ mflr %r9 stw %r28,-16(%r10) stw %r29,-12(%r10) stw %r30, -8(%r10) stw %r31, -4(%r10) stw %r9, 4(%r10) .cfi_offset 65, 4 .cfi_offset 31, -4 .cfi_offset 30, -8 .cfi_offset 29, -12 .cfi_offset 28, -16 /* Save arguments over call... */ stw %r7, -20(%r10) /* closure, */ mr %r31,%r6 /* flags, */ mr %r30,%r5 /* rvalue, */ mr %r29,%r4 /* function address, */ mr %r28,%r10 /* our AP. */ .cfi_def_cfa_register 28 /* Call ffi_prep_args_SYSV. */ mr %r4,%r1 bl ffi_prep_args_SYSV@local /* Now do the call. */ /* Set up cr1 with bits 4-7 of the flags. */ mtcrf 0x40,%r31 /* Get the address to call into CTR. */ mtctr %r29 /* Load all those argument registers. */ lwz %r3,-24-(8*4)(%r28) lwz %r4,-24-(7*4)(%r28) lwz %r5,-24-(6*4)(%r28) lwz %r6,-24-(5*4)(%r28) bf- 5,1f nop lwz %r7,-24-(4*4)(%r28) lwz %r8,-24-(3*4)(%r28) lwz %r9,-24-(2*4)(%r28) lwz %r10,-24-(1*4)(%r28) nop 1: #ifndef __NO_FPRS__ /* Load all the FP registers. */ bf- 6,2f lfd %f1,-24-(8*4)-(8*8)(%r28) lfd %f2,-24-(8*4)-(7*8)(%r28) lfd %f3,-24-(8*4)-(6*8)(%r28) lfd %f4,-24-(8*4)-(5*8)(%r28) nop lfd %f5,-24-(8*4)-(4*8)(%r28) lfd %f6,-24-(8*4)-(3*8)(%r28) lfd %f7,-24-(8*4)-(2*8)(%r28) lfd %f8,-24-(8*4)-(1*8)(%r28) #endif 2: /* Make the call. */ lwz %r11, -20(%r28) bctrl /* Now, deal with the return value. */ mtcrf 0x01,%r31 /* cr7 */ bt- 31,L(small_struct_return_value) bt- 30,L(done_return_value) #ifndef __NO_FPRS__ bt- 29,L(fp_return_value) #endif stw %r3,0(%r30) bf+ 28,L(done_return_value) stw %r4,4(%r30) mtcrf 0x02,%r31 /* cr6 */ bf 27,L(done_return_value) stw %r5,8(%r30) stw %r6,12(%r30) /* Fall through... */ L(done_return_value): /* Restore the registers we used and return. */ lwz %r9, 4(%r28) lwz %r31, -4(%r28) mtlr %r9 lwz %r30, -8(%r28) lwz %r29,-12(%r28) lwz %r28,-16(%r28) .cfi_remember_state /* At this point we don't have a cfa register. Say all our saved regs have been restored. */ .cfi_same_value 65 .cfi_same_value 31 .cfi_same_value 30 .cfi_same_value 29 .cfi_same_value 28 /* Hopefully this works.. */ .cfi_def_cfa_register 1 .cfi_offset 1, 0 lwz %r1,0(%r1) .cfi_same_value 1 blr #ifndef __NO_FPRS__ L(fp_return_value): .cfi_restore_state bf 28,L(float_return_value) stfd %f1,0(%r30) mtcrf 0x02,%r31 /* cr6 */ bf 27,L(done_return_value) stfd %f2,8(%r30) b L(done_return_value) L(float_return_value): stfs %f1,0(%r30) b L(done_return_value) #endif L(small_struct_return_value): /* * The C code always allocates a properly-aligned 8-byte bounce * buffer to make this assembly code very simple. Just write out * r3 and r4 to the buffer to allow the C code to handle the rest. */ stw %r3, 0(%r30) stw %r4, 4(%r30) b L(done_return_value) .cfi_endproc END(ffi_call_SYSV) #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif #endif ====================File: src/prep_cif.c==================== /* ----------------------------------------------------------------------- prep_cif.c - Copyright (c) 2011, 2012 Anthony Green Copyright (c) 1996, 1998, 2007 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 THE AUTHORS OR COPYRIGHT HOLDERS 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 #include #include /* Round up to FFI_SIZEOF_ARG. */ #define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG) /* Perform machine independent initialization of aggregate type specifications. */ static ffi_status initialize_aggregate(ffi_type *arg, size_t *offsets) { ffi_type **ptr; if (UNLIKELY(arg == NULL || arg->elements == NULL)) return FFI_BAD_TYPEDEF; arg->size = 0; arg->alignment = 0; ptr = &(arg->elements[0]); if (UNLIKELY(ptr == 0)) return FFI_BAD_TYPEDEF; while ((*ptr) != NULL) { if (UNLIKELY(((*ptr)->size == 0) && (initialize_aggregate((*ptr), NULL) != FFI_OK))) return FFI_BAD_TYPEDEF; /* Perform a sanity check on the argument type */ FFI_ASSERT_VALID_TYPE(*ptr); arg->size = FFI_ALIGN(arg->size, (*ptr)->alignment); if (offsets) *offsets++ = arg->size; arg->size += (*ptr)->size; arg->alignment = (arg->alignment > (*ptr)->alignment) ? arg->alignment : (*ptr)->alignment; ptr++; } /* Structure size includes tail padding. This is important for structures that fit in one register on ABIs like the PowerPC64 Linux ABI that right justify small structs in a register. It's also needed for nested structure layout, for example struct A { long a; char b; }; struct B { struct A x; char y; }; should find y at an offset of 2*sizeof(long) and result in a total size of 3*sizeof(long). */ arg->size = FFI_ALIGN (arg->size, arg->alignment); /* On some targets, the ABI defines that structures have an additional alignment beyond the "natural" one based on their elements. */ #ifdef FFI_AGGREGATE_ALIGNMENT if (FFI_AGGREGATE_ALIGNMENT > arg->alignment) arg->alignment = FFI_AGGREGATE_ALIGNMENT; #endif if (arg->size == 0) return FFI_BAD_TYPEDEF; else return FFI_OK; } #ifndef __CRIS__ /* The CRIS ABI specifies structure elements to have byte alignment only, so it completely overrides this functions, which assumes "natural" alignment and padding. */ /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ /* For non variadic functions isvariadic should be 0 and nfixedargs==ntotalargs. For variadic calls, isvariadic should be 1 and nfixedargs and ntotalargs set as appropriate. nfixedargs must always be >=1 */ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, unsigned int isvariadic, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **atypes) { unsigned bytes = 0; unsigned int i; ffi_type **ptr; FFI_ASSERT(cif != NULL); FFI_ASSERT((!isvariadic) || (nfixedargs >= 1)); FFI_ASSERT(nfixedargs <= ntotalargs); if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)) return FFI_BAD_ABI; cif->abi = abi; cif->arg_types = atypes; cif->nargs = ntotalargs; cif->rtype = rtype; cif->flags = 0; #ifdef _M_ARM64 cif->is_variadic = isvariadic; #endif #if HAVE_LONG_DOUBLE_VARIANT ffi_prep_types (abi); #endif /* Initialize the return type if necessary */ if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype, NULL) != FFI_OK)) return FFI_BAD_TYPEDEF; #ifndef FFI_TARGET_HAS_COMPLEX_TYPE if (rtype->type == FFI_TYPE_COMPLEX) abort(); #endif /* Perform a sanity check on the return type */ FFI_ASSERT_VALID_TYPE(cif->rtype); /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */ #if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT #ifdef TILE && (cif->rtype->size > 10 * FFI_SIZEOF_ARG) #endif #ifdef XTENSA && (cif->rtype->size > 16) #endif #ifdef NIOS2 && (cif->rtype->size > 8) #endif ) bytes = STACK_ARG_SIZE(sizeof(void*)); #endif for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) { /* Initialize any uninitialized aggregate type definitions */ if (((*ptr)->size == 0) && (initialize_aggregate((*ptr), NULL) != FFI_OK)) return FFI_BAD_TYPEDEF; #ifndef FFI_TARGET_HAS_COMPLEX_TYPE if ((*ptr)->type == FFI_TYPE_COMPLEX) abort(); #endif /* Perform a sanity check on the argument type, do this check after the initialization. */ FFI_ASSERT_VALID_TYPE(*ptr); #if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION { /* Add any padding if necessary */ if (((*ptr)->alignment - 1) & bytes) bytes = (unsigned)FFI_ALIGN(bytes, (*ptr)->alignment); #ifdef TILE if (bytes < 10 * FFI_SIZEOF_ARG && bytes + STACK_ARG_SIZE((*ptr)->size) > 10 * FFI_SIZEOF_ARG) { /* An argument is never split between the 10 parameter registers and the stack. */ bytes = 10 * FFI_SIZEOF_ARG; } #endif #ifdef XTENSA if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4) bytes = 6*4; #endif bytes += (unsigned int)STACK_ARG_SIZE((*ptr)->size); } #endif } cif->bytes = bytes; /* Perform machine dependent cif processing */ #ifdef FFI_TARGET_SPECIFIC_VARIADIC if (isvariadic) return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs); #endif return ffi_prep_cif_machdep(cif); } #endif /* not __CRIS__ */ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes) { return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes); } ffi_status ffi_prep_cif_var(ffi_cif *cif, ffi_abi abi, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **atypes) { return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes); } #if FFI_CLOSURES ffi_status ffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) { return ffi_prep_closure_loc (closure, cif, fun, user_data, closure); } #endif ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets) { if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)) return FFI_BAD_ABI; if (struct_type->type != FFI_TYPE_STRUCT) return FFI_BAD_TYPEDEF; #if HAVE_LONG_DOUBLE_VARIANT ffi_prep_types (abi); #endif return initialize_aggregate(struct_type, offsets); } ====================File: src/raw_api.c==================== /* ----------------------------------------------------------------------- raw_api.c - Copyright (c) 1999, 2008 Red Hat, Inc. Author: Kresten Krab Thorup 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ /* This file defines generic functions for use with the raw api. */ #include #include #if !FFI_NO_RAW_API size_t ffi_raw_size (ffi_cif *cif) { size_t result = 0; int i; ffi_type **at = cif->arg_types; for (i = cif->nargs-1; i >= 0; i--, at++) { #if !FFI_NO_STRUCTS if ((*at)->type == FFI_TYPE_STRUCT) result += FFI_ALIGN (sizeof (void*), FFI_SIZEOF_ARG); else #endif result += FFI_ALIGN ((*at)->size, FFI_SIZEOF_ARG); } return result; } void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args) { unsigned i; ffi_type **tp = cif->arg_types; #if WORDS_BIGENDIAN for (i = 0; i < cif->nargs; i++, tp++, args++) { switch ((*tp)->type) { case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 1); break; case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 2); break; #if FFI_SIZEOF_ARG >= 4 case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 4); break; #endif #if !FFI_NO_STRUCTS case FFI_TYPE_STRUCT: *args = (raw++)->ptr; break; #endif case FFI_TYPE_COMPLEX: *args = (raw++)->ptr; break; case FFI_TYPE_POINTER: *args = (void*) &(raw++)->ptr; break; default: *args = raw; raw += FFI_ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; } } #else /* WORDS_BIGENDIAN */ #if !PDP /* then assume little endian */ for (i = 0; i < cif->nargs; i++, tp++, args++) { #if !FFI_NO_STRUCTS if ((*tp)->type == FFI_TYPE_STRUCT) { *args = (raw++)->ptr; } else #endif if ((*tp)->type == FFI_TYPE_COMPLEX) { *args = (raw++)->ptr; } else { *args = (void*) raw; raw += FFI_ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*); } } #else #error "pdp endian not supported" #endif /* ! PDP */ #endif /* WORDS_BIGENDIAN */ } void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw) { unsigned i; ffi_type **tp = cif->arg_types; for (i = 0; i < cif->nargs; i++, tp++, args++) { switch ((*tp)->type) { case FFI_TYPE_UINT8: (raw++)->uint = *(UINT8*) (*args); break; case FFI_TYPE_SINT8: (raw++)->sint = *(SINT8*) (*args); break; case FFI_TYPE_UINT16: (raw++)->uint = *(UINT16*) (*args); break; case FFI_TYPE_SINT16: (raw++)->sint = *(SINT16*) (*args); break; #if FFI_SIZEOF_ARG >= 4 case FFI_TYPE_UINT32: (raw++)->uint = *(UINT32*) (*args); break; case FFI_TYPE_SINT32: (raw++)->sint = *(SINT32*) (*args); break; #endif #if !FFI_NO_STRUCTS case FFI_TYPE_STRUCT: (raw++)->ptr = *args; break; #endif case FFI_TYPE_COMPLEX: (raw++)->ptr = *args; break; case FFI_TYPE_POINTER: (raw++)->ptr = **(void***) args; break; default: memcpy ((void*) raw->data, (void*)*args, (*tp)->size); raw += FFI_ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; } } } #if !FFI_NATIVE_RAW_API /* This is a generic definition of ffi_raw_call, to be used if the * native system does not provide a machine-specific implementation. * Having this, allows code to be written for the raw API, without * the need for system-specific code to handle input in that format; * these following couple of functions will handle the translation forth * and back automatically. */ void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *raw) { void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); ffi_raw_to_ptrarray (cif, raw, avalue); ffi_call (cif, fn, rvalue, avalue); } #if FFI_CLOSURES /* base system provides closures */ static void ffi_translate_args (ffi_cif *cif, void *rvalue, void **avalue, void *user_data) { ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif)); ffi_raw_closure *cl = (ffi_raw_closure*)user_data; ffi_ptrarray_to_raw (cif, avalue, raw); (*cl->fun) (cif, rvalue, raw, cl->user_data); } ffi_status ffi_prep_raw_closure_loc (ffi_raw_closure* cl, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data, void *codeloc) { ffi_status status; status = ffi_prep_closure_loc ((ffi_closure*) cl, cif, &ffi_translate_args, codeloc, codeloc); if (status == FFI_OK) { cl->fun = fun; cl->user_data = user_data; } return status; } #endif /* FFI_CLOSURES */ #endif /* !FFI_NATIVE_RAW_API */ #if FFI_CLOSURES /* Again, here is the generic version of ffi_prep_raw_closure, which * will install an intermediate "hub" for translation of arguments from * the pointer-array format, to the raw format */ ffi_status ffi_prep_raw_closure (ffi_raw_closure* cl, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data) { return ffi_prep_raw_closure_loc (cl, cif, fun, user_data, cl); } #endif /* FFI_CLOSURES */ #endif /* !FFI_NO_RAW_API */ ====================File: src/types.c==================== /* ----------------------------------------------------------------------- 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 THE AUTHORS OR COPYRIGHT HOLDERS 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. ----------------------------------------------------------------------- */ /* Hide the basic type definitions from the header file, so that we can redefine them here as "const". */ #define LIBFFI_HIDE_BASIC_TYPES #include #include /* Type definitions */ #define FFI_TYPEDEF(name, type, id, maybe_const)\ struct struct_align_##name { \ char c; \ type x; \ }; \ FFI_EXTERN \ maybe_const ffi_type ffi_type_##name = { \ sizeof(type), \ offsetof(struct struct_align_##name, x), \ id, NULL \ } #define FFI_COMPLEX_TYPEDEF(name, type, maybe_const) \ static ffi_type *ffi_elements_complex_##name [2] = { \ (ffi_type *)(&ffi_type_##name), NULL \ }; \ struct struct_align_complex_##name { \ char c; \ _Complex type x; \ }; \ FFI_EXTERN \ maybe_const ffi_type ffi_type_complex_##name = { \ sizeof(_Complex type), \ offsetof(struct struct_align_complex_##name, x), \ FFI_TYPE_COMPLEX, \ (ffi_type **)ffi_elements_complex_##name \ } /* Size and alignment are fake here. They must not be 0. */ FFI_EXTERN const ffi_type ffi_type_void = { 1, 1, FFI_TYPE_VOID, NULL }; FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8, const); FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8, const); FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16, const); FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16, const); FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32, const); FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32, const); FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64, const); FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64, const); FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER, const); FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT, const); FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE, const); #if !defined HAVE_LONG_DOUBLE_VARIANT || defined __alpha__ #define FFI_LDBL_CONST const #else #define FFI_LDBL_CONST #endif #ifdef __alpha__ /* Even if we're not configured to default to 128-bit long double, maintain binary compatibility, as -mlong-double-128 can be used at any time. */ /* Validate the hard-coded number below. */ # if defined(__LONG_DOUBLE_128__) && FFI_TYPE_LONGDOUBLE != 4 # error FFI_TYPE_LONGDOUBLE out of date # endif const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL }; #elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE, FFI_LDBL_CONST); #endif #ifdef FFI_TARGET_HAS_COMPLEX_TYPE FFI_COMPLEX_TYPEDEF(float, float, const); FFI_COMPLEX_TYPEDEF(double, double, const); #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE FFI_COMPLEX_TYPEDEF(longdouble, long double, FFI_LDBL_CONST); #endif #endif ====================File: src/x86/ffi.c==================== /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2017 Anthony Green Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc. Copyright (c) 2002 Ranjit Mathew Copyright (c) 2002 Bo Thorsen Copyright (c) 2002 Roger Sayle Copyright (C) 2008, 2010 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #if defined(__i386__) || defined(_M_IX86) #include #include #include #include #include "internal.h" /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; all further uses in this file will refer to the 80-bit type. */ #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE # if FFI_TYPE_LONGDOUBLE != 4 # error FFI_TYPE_LONGDOUBLE out of date # endif #else # undef FFI_TYPE_LONGDOUBLE # define FFI_TYPE_LONGDOUBLE 4 #endif #if defined(__GNUC__) && !defined(__declspec) # define __declspec(x) __attribute__((x)) #endif #if defined(_MSC_VER) && defined(_M_IX86) /* Stack is not 16-byte aligned on Windows. */ #define STACK_ALIGN(bytes) (bytes) #else #define STACK_ALIGN(bytes) FFI_ALIGN (bytes, 16) #endif /* Perform machine dependent cif processing. */ ffi_status FFI_HIDDEN ffi_prep_cif_machdep(ffi_cif *cif) { size_t bytes = 0; int i, n, flags, cabi = cif->abi; switch (cabi) { case FFI_SYSV: case FFI_STDCALL: case FFI_THISCALL: case FFI_FASTCALL: case FFI_MS_CDECL: case FFI_PASCAL: case FFI_REGISTER: break; default: return FFI_BAD_ABI; } switch (cif->rtype->type) { case FFI_TYPE_VOID: flags = X86_RET_VOID; break; case FFI_TYPE_FLOAT: flags = X86_RET_FLOAT; break; case FFI_TYPE_DOUBLE: flags = X86_RET_DOUBLE; break; case FFI_TYPE_LONGDOUBLE: flags = X86_RET_LDOUBLE; break; case FFI_TYPE_UINT8: flags = X86_RET_UINT8; break; case FFI_TYPE_UINT16: flags = X86_RET_UINT16; break; case FFI_TYPE_SINT8: flags = X86_RET_SINT8; break; case FFI_TYPE_SINT16: flags = X86_RET_SINT16; break; case FFI_TYPE_INT: case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_POINTER: flags = X86_RET_INT32; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: flags = X86_RET_INT64; break; case FFI_TYPE_STRUCT: #ifndef X86 /* ??? This should be a different ABI rather than an ifdef. */ if (cif->rtype->size == 1) flags = X86_RET_STRUCT_1B; else if (cif->rtype->size == 2) flags = X86_RET_STRUCT_2B; else if (cif->rtype->size == 4) flags = X86_RET_INT32; else if (cif->rtype->size == 8) flags = X86_RET_INT64; else #endif { do_struct: switch (cabi) { case FFI_THISCALL: case FFI_FASTCALL: case FFI_STDCALL: case FFI_MS_CDECL: flags = X86_RET_STRUCTARG; break; default: flags = X86_RET_STRUCTPOP; break; } /* Allocate space for return value pointer. */ bytes += FFI_ALIGN (sizeof(void*), FFI_SIZEOF_ARG); } break; case FFI_TYPE_COMPLEX: switch (cif->rtype->elements[0]->type) { case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: goto do_struct; case FFI_TYPE_FLOAT: case FFI_TYPE_INT: case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: flags = X86_RET_INT64; break; case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: flags = X86_RET_INT32; break; case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: flags = X86_RET_STRUCT_2B; break; default: return FFI_BAD_TYPEDEF; } break; default: return FFI_BAD_TYPEDEF; } cif->flags = flags; for (i = 0, n = cif->nargs; i < n; i++) { ffi_type *t = cif->arg_types[i]; bytes = FFI_ALIGN (bytes, t->alignment); bytes += FFI_ALIGN (t->size, FFI_SIZEOF_ARG); } cif->bytes = bytes; return FFI_OK; } static ffi_arg extend_basic_type(void *arg, int type) { switch (type) { case FFI_TYPE_SINT8: return *(SINT8 *)arg; case FFI_TYPE_UINT8: return *(UINT8 *)arg; case FFI_TYPE_SINT16: return *(SINT16 *)arg; case FFI_TYPE_UINT16: return *(UINT16 *)arg; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_POINTER: case FFI_TYPE_FLOAT: return *(UINT32 *)arg; default: abort(); } } struct call_frame { void *ebp; /* 0 */ void *retaddr; /* 4 */ void (*fn)(void); /* 8 */ int flags; /* 12 */ void *rvalue; /* 16 */ unsigned regs[3]; /* 20-28 */ }; struct abi_params { int dir; /* parameter growth direction */ int static_chain; /* the static chain register used by gcc */ int nregs; /* number of register parameters */ int regs[3]; }; static const struct abi_params abi_params[FFI_LAST_ABI] = { [FFI_SYSV] = { 1, R_ECX, 0 }, [FFI_THISCALL] = { 1, R_EAX, 1, { R_ECX } }, [FFI_FASTCALL] = { 1, R_EAX, 2, { R_ECX, R_EDX } }, [FFI_STDCALL] = { 1, R_ECX, 0 }, [FFI_PASCAL] = { -1, R_ECX, 0 }, /* ??? No defined static chain; gcc does not support REGISTER. */ [FFI_REGISTER] = { -1, R_ECX, 3, { R_EAX, R_EDX, R_ECX } }, [FFI_MS_CDECL] = { 1, R_ECX, 0 } }; #ifdef HAVE_FASTCALL #ifdef _MSC_VER #define FFI_DECLARE_FASTCALL __fastcall #else #define FFI_DECLARE_FASTCALL __declspec(fastcall) #endif #else #define FFI_DECLARE_FASTCALL #endif extern void FFI_DECLARE_FASTCALL ffi_call_i386(struct call_frame *, char *) FFI_HIDDEN; static void ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { size_t rsize, bytes; struct call_frame *frame; char *stack, *argp; ffi_type **arg_types; int flags, cabi, i, n, dir, narg_reg; const struct abi_params *pabi; flags = cif->flags; cabi = cif->abi; pabi = &abi_params[cabi]; dir = pabi->dir; rsize = 0; if (rvalue == NULL) { switch (flags) { case X86_RET_FLOAT: case X86_RET_DOUBLE: case X86_RET_LDOUBLE: case X86_RET_STRUCTPOP: case X86_RET_STRUCTARG: /* The float cases need to pop the 387 stack. The struct cases need to pass a valid pointer to the callee. */ rsize = cif->rtype->size; break; default: /* We can pretend that the callee returns nothing. */ flags = X86_RET_VOID; break; } } bytes = STACK_ALIGN (cif->bytes); stack = alloca(bytes + sizeof(*frame) + rsize); argp = (dir < 0 ? stack + bytes : stack); frame = (struct call_frame *)(stack + bytes); if (rsize) rvalue = frame + 1; frame->fn = fn; frame->flags = flags; frame->rvalue = rvalue; frame->regs[pabi->static_chain] = (unsigned)closure; narg_reg = 0; switch (flags) { case X86_RET_STRUCTARG: /* The pointer is passed as the first argument. */ if (pabi->nregs > 0) { frame->regs[pabi->regs[0]] = (unsigned)rvalue; narg_reg = 1; break; } /* fallthru */ case X86_RET_STRUCTPOP: *(void **)argp = rvalue; argp += sizeof(void *); break; } arg_types = cif->arg_types; for (i = 0, n = cif->nargs; i < n; i++) { ffi_type *ty = arg_types[i]; void *valp = avalue[i]; size_t z = ty->size; int t = ty->type; if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT) { ffi_arg val = extend_basic_type (valp, t); if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs) frame->regs[pabi->regs[narg_reg++]] = val; else if (dir < 0) { argp -= 4; *(ffi_arg *)argp = val; } else { *(ffi_arg *)argp = val; argp += 4; } } else { size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG); size_t align = FFI_SIZEOF_ARG; /* Issue 434: For thiscall and fastcall, if the paramter passed as 64-bit integer or struct, all following integer paramters will be passed on stack. */ if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL) && (t == FFI_TYPE_SINT64 || t == FFI_TYPE_UINT64 || t == FFI_TYPE_STRUCT)) narg_reg = 2; /* Alignment rules for arguments are quite complex. Vectors and structures with 16 byte alignment get it. Note that long double on Darwin does have 16 byte alignment, and does not get this alignment if passed directly; a structure with a long double inside, however, would get 16 byte alignment. Since libffi does not support vectors, we need non concern ourselves with other cases. */ if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) align = 16; if (dir < 0) { /* ??? These reverse argument ABIs are probably too old to have cared about alignment. Someone should check. */ argp -= za; memcpy (argp, valp, z); } else { argp = (char *)FFI_ALIGN (argp, align); memcpy (argp, valp, z); argp += za; } } } FFI_ASSERT (dir > 0 || argp == stack); ffi_call_i386 (frame, stack); } void ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { ffi_call_int (cif, fn, rvalue, avalue, NULL); } void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { ffi_call_int (cif, fn, rvalue, avalue, closure); } /** private members **/ void FFI_HIDDEN ffi_closure_i386(void); void FFI_HIDDEN ffi_closure_STDCALL(void); void FFI_HIDDEN ffi_closure_REGISTER(void); struct closure_frame { unsigned rettemp[4]; /* 0 */ unsigned regs[3]; /* 16-24 */ ffi_cif *cif; /* 28 */ void (*fun)(ffi_cif*,void*,void**,void*); /* 32 */ void *user_data; /* 36 */ }; int FFI_HIDDEN FFI_DECLARE_FASTCALL ffi_closure_inner (struct closure_frame *frame, char *stack) { ffi_cif *cif = frame->cif; int cabi, i, n, flags, dir, narg_reg; const struct abi_params *pabi; ffi_type **arg_types; char *argp; void *rvalue; void **avalue; cabi = cif->abi; flags = cif->flags; narg_reg = 0; rvalue = frame->rettemp; pabi = &abi_params[cabi]; dir = pabi->dir; argp = (dir < 0 ? stack + STACK_ALIGN (cif->bytes) : stack); switch (flags) { case X86_RET_STRUCTARG: if (pabi->nregs > 0) { rvalue = (void *)frame->regs[pabi->regs[0]]; narg_reg = 1; frame->rettemp[0] = (unsigned)rvalue; break; } /* fallthru */ case X86_RET_STRUCTPOP: rvalue = *(void **)argp; argp += sizeof(void *); frame->rettemp[0] = (unsigned)rvalue; break; } n = cif->nargs; avalue = alloca(sizeof(void *) * n); arg_types = cif->arg_types; for (i = 0; i < n; ++i) { ffi_type *ty = arg_types[i]; size_t z = ty->size; int t = ty->type; void *valp; if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT) { if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs) valp = &frame->regs[pabi->regs[narg_reg++]]; else if (dir < 0) { argp -= 4; valp = argp; } else { valp = argp; argp += 4; } } else { size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG); size_t align = FFI_SIZEOF_ARG; /* See the comment in ffi_call_int. */ if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) align = 16; /* Issue 434: For thiscall and fastcall, if the paramter passed as 64-bit integer or struct, all following integer paramters will be passed on stack. */ if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL) && (t == FFI_TYPE_SINT64 || t == FFI_TYPE_UINT64 || t == FFI_TYPE_STRUCT)) narg_reg = 2; if (dir < 0) { /* ??? These reverse argument ABIs are probably too old to have cared about alignment. Someone should check. */ argp -= za; valp = argp; } else { argp = (char *)FFI_ALIGN (argp, align); valp = argp; argp += za; } } avalue[i] = valp; } frame->fun (cif, rvalue, avalue, frame->user_data); if (cabi == FFI_STDCALL) return flags + (cif->bytes << X86_RET_POP_SHIFT); else return flags; } ffi_status ffi_prep_closure_loc (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc) { char *tramp = closure->tramp; void (*dest)(void); int op = 0xb8; /* movl imm, %eax */ switch (cif->abi) { case FFI_SYSV: case FFI_THISCALL: case FFI_FASTCALL: case FFI_MS_CDECL: dest = ffi_closure_i386; break; case FFI_STDCALL: case FFI_PASCAL: dest = ffi_closure_STDCALL; break; case FFI_REGISTER: dest = ffi_closure_REGISTER; op = 0x68; /* pushl imm */ break; default: return FFI_BAD_ABI; } /* movl or pushl immediate. */ tramp[0] = op; *(void **)(tramp + 1) = codeloc; /* jmp dest */ tramp[5] = 0xe9; *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10); closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK; } void FFI_HIDDEN ffi_go_closure_EAX(void); void FFI_HIDDEN ffi_go_closure_ECX(void); void FFI_HIDDEN ffi_go_closure_STDCALL(void); ffi_status ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*)) { void (*dest)(void); switch (cif->abi) { case FFI_SYSV: case FFI_MS_CDECL: dest = ffi_go_closure_ECX; break; case FFI_THISCALL: case FFI_FASTCALL: dest = ffi_go_closure_EAX; break; case FFI_STDCALL: case FFI_PASCAL: dest = ffi_go_closure_STDCALL; break; case FFI_REGISTER: default: return FFI_BAD_ABI; } closure->tramp = dest; closure->cif = cif; closure->fun = fun; return FFI_OK; } /* ------- Native raw API support -------------------------------- */ #if !FFI_NO_RAW_API void FFI_HIDDEN ffi_closure_raw_SYSV(void); void FFI_HIDDEN ffi_closure_raw_THISCALL(void); ffi_status ffi_prep_raw_closure_loc (ffi_raw_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data, void *codeloc) { char *tramp = closure->tramp; void (*dest)(void); 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--) switch (cif->arg_types[i]->type) { case FFI_TYPE_STRUCT: case FFI_TYPE_LONGDOUBLE: return FFI_BAD_TYPEDEF; } switch (cif->abi) { case FFI_THISCALL: dest = ffi_closure_raw_THISCALL; break; case FFI_SYSV: dest = ffi_closure_raw_SYSV; break; default: return FFI_BAD_ABI; } /* movl imm, %eax. */ tramp[0] = 0xb8; *(void **)(tramp + 1) = codeloc; /* jmp dest */ tramp[5] = 0xe9; *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10); closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK; } void ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue) { size_t rsize, bytes; struct call_frame *frame; char *stack, *argp; ffi_type **arg_types; int flags, cabi, i, n, narg_reg; const struct abi_params *pabi; flags = cif->flags; cabi = cif->abi; pabi = &abi_params[cabi]; rsize = 0; if (rvalue == NULL) { switch (flags) { case X86_RET_FLOAT: case X86_RET_DOUBLE: case X86_RET_LDOUBLE: case X86_RET_STRUCTPOP: case X86_RET_STRUCTARG: /* The float cases need to pop the 387 stack. The struct cases need to pass a valid pointer to the callee. */ rsize = cif->rtype->size; break; default: /* We can pretend that the callee returns nothing. */ flags = X86_RET_VOID; break; } } bytes = STACK_ALIGN (cif->bytes); argp = stack = (void *)((uintptr_t)alloca(bytes + sizeof(*frame) + rsize + 15) & ~16); frame = (struct call_frame *)(stack + bytes); if (rsize) rvalue = frame + 1; frame->fn = fn; frame->flags = flags; frame->rvalue = rvalue; narg_reg = 0; switch (flags) { case X86_RET_STRUCTARG: /* The pointer is passed as the first argument. */ if (pabi->nregs > 0) { frame->regs[pabi->regs[0]] = (unsigned)rvalue; narg_reg = 1; break; } /* fallthru */ case X86_RET_STRUCTPOP: *(void **)argp = rvalue; argp += sizeof(void *); bytes -= sizeof(void *); break; } arg_types = cif->arg_types; for (i = 0, n = cif->nargs; narg_reg < pabi->nregs && i < n; i++) { ffi_type *ty = arg_types[i]; size_t z = ty->size; int t = ty->type; if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT && t != FFI_TYPE_FLOAT) { ffi_arg val = extend_basic_type (avalue, t); frame->regs[pabi->regs[narg_reg++]] = val; z = FFI_SIZEOF_ARG; } else { memcpy (argp, avalue, z); z = FFI_ALIGN (z, FFI_SIZEOF_ARG); argp += z; } avalue += z; bytes -= z; } if (i < n) memcpy (argp, avalue, bytes); ffi_call_i386 (frame, stack); } #endif /* !FFI_NO_RAW_API */ #endif /* __i386__ */ ====================File: src/x86/ffi64.c==================== /* ----------------------------------------------------------------------- ffi64.c - Copyright (c) 2011, 2018 Anthony Green Copyright (c) 2013 The Written Word, Inc. Copyright (c) 2008, 2010 Red Hat, Inc. Copyright (c) 2002, 2007 Bo Thorsen 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 THE AUTHORS OR COPYRIGHT HOLDERS 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 #include #include #include #include #include "internal64.h" #ifdef __x86_64__ #define MAX_GPR_REGS 6 #define MAX_SSE_REGS 8 #if defined(__INTEL_COMPILER) #include "xmmintrin.h" #define UINT128 __m128 #else #if defined(__SUNPRO_C) #error #include #define UINT128 __m128i #else #define UINT128 __int128_t #endif #endif union big_int_union { UINT32 i32; UINT64 i64; UINT128 i128; }; struct register_args { /* Registers for argument passing. */ UINT64 gpr[MAX_GPR_REGS]; union big_int_union sse[MAX_SSE_REGS]; UINT64 rax; /* ssecount */ UINT64 r10; /* static chain */ }; extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, void *raddr, void (*fnaddr)(void)) FFI_HIDDEN; /* 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 reformatting 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 size_t 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: do_integer: { size_t size = byte_offset + type->size; if (size <= 4) { classes[0] = X86_64_INTEGERSI_CLASS; return 1; } else if (size <= 8) { classes[0] = X86_64_INTEGER_CLASS; return 1; } else if (size <= 12) { classes[0] = X86_64_INTEGER_CLASS; classes[1] = X86_64_INTEGERSI_CLASS; return 2; } else if (size <= 16) { classes[0] = classes[1] = X86_64_INTEGER_CLASS; return 2; } else FFI_ASSERT (0); } case FFI_TYPE_FLOAT: if (!(byte_offset % 8)) 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; #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: classes[0] = X86_64_X87_CLASS; classes[1] = X86_64_X87UP_CLASS; return 2; #endif case FFI_TYPE_STRUCT: { const size_t UNITS_PER_WORD = 8; size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; ffi_type **ptr; unsigned int i; enum x86_64_reg_class subclasses[MAX_CLASSES]; /* If the struct is larger than 32 bytes, pass it on the stack. */ if (type->size > 32) return 0; for (i = 0; i < words; i++) classes[i] = X86_64_NO_CLASS; /* Zero sized arrays or structures are NO_CLASS. We return 0 to signalize memory class, so handle it as special case. */ if (!words) { case FFI_TYPE_VOID: classes[0] = X86_64_NO_CLASS; return 1; } /* Merge the fields of structure. */ for (ptr = type->elements; *ptr != NULL; ptr++) { size_t num; byte_offset = FFI_ALIGN (byte_offset, (*ptr)->alignment); num = classify_argument (*ptr, subclasses, byte_offset % 8); if (num == 0) return 0; for (i = 0; i < num; i++) { size_t pos = byte_offset / 8; classes[i + pos] = merge_classes (subclasses[i], classes[i + pos]); } byte_offset += (*ptr)->size; } if (words > 2) { /* When size > 16 bytes, if the first one isn't X86_64_SSE_CLASS or any other ones aren't X86_64_SSEUP_CLASS, everything should be passed in memory. */ if (classes[0] != X86_64_SSE_CLASS) return 0; for (i = 1; i < words; i++) if (classes[i] != X86_64_SSEUP_CLASS) return 0; } /* 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 or X86_64_SSEUP_CLASS. */ if (i > 1 && classes[i] == X86_64_SSEUP_CLASS && classes[i - 1] != X86_64_SSE_CLASS && classes[i - 1] != X86_64_SSEUP_CLASS) { /* The first one should never be X86_64_SSEUP_CLASS. */ FFI_ASSERT (i != 0); classes[i] = X86_64_SSE_CLASS; } /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS, everything should be passed in memory. */ if (i > 1 && classes[i] == X86_64_X87UP_CLASS && (classes[i - 1] != X86_64_X87_CLASS)) { /* The first one should never be X86_64_X87UP_CLASS. */ FFI_ASSERT (i != 0); return 0; } } return words; } case FFI_TYPE_COMPLEX: { ffi_type *inner = type->elements[0]; switch (inner->type) { case FFI_TYPE_INT: 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: goto do_integer; case FFI_TYPE_FLOAT: classes[0] = X86_64_SSE_CLASS; if (byte_offset % 8) { classes[1] = X86_64_SSESF_CLASS; return 2; } return 1; case FFI_TYPE_DOUBLE: classes[0] = classes[1] = X86_64_SSEDF_CLASS; return 2; #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: classes[0] = X86_64_COMPLEX_X87_CLASS; return 1; #endif } } } abort(); } /* Examine the argument and return set number of register required in each class. Return zero iff parameter should be passed in memory, otherwise the number of registers. */ static size_t examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], _Bool in_return, int *pngpr, int *pnsse) { size_t n; unsigned int i; int ngpr, nsse; n = classify_argument (type, classes, 0); if (n == 0) return 0; ngpr = nsse = 0; for (i = 0; i < n; ++i) switch (classes[i]) { case X86_64_INTEGER_CLASS: case X86_64_INTEGERSI_CLASS: ngpr++; break; case X86_64_SSE_CLASS: case X86_64_SSESF_CLASS: case X86_64_SSEDF_CLASS: nsse++; break; case X86_64_NO_CLASS: case X86_64_SSEUP_CLASS: break; case X86_64_X87_CLASS: case X86_64_X87UP_CLASS: case X86_64_COMPLEX_X87_CLASS: return in_return != 0; default: abort (); } *pngpr = ngpr; *pnsse = nsse; return n; } /* Perform machine dependent cif processing. */ #ifndef __ILP32__ extern ffi_status ffi_prep_cif_machdep_efi64(ffi_cif *cif); #endif ffi_status FFI_HIDDEN ffi_prep_cif_machdep (ffi_cif *cif) { int gprcount, ssecount, i, avn, ngpr, nsse; unsigned flags; enum x86_64_reg_class classes[MAX_CLASSES]; size_t bytes, n, rtype_size; ffi_type *rtype; #ifndef __ILP32__ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64) return ffi_prep_cif_machdep_efi64(cif); #endif if (cif->abi != FFI_UNIX64) return FFI_BAD_ABI; gprcount = ssecount = 0; rtype = cif->rtype; rtype_size = rtype->size; switch (rtype->type) { case FFI_TYPE_VOID: flags = UNIX64_RET_VOID; break; case FFI_TYPE_UINT8: flags = UNIX64_RET_UINT8; break; case FFI_TYPE_SINT8: flags = UNIX64_RET_SINT8; break; case FFI_TYPE_UINT16: flags = UNIX64_RET_UINT16; break; case FFI_TYPE_SINT16: flags = UNIX64_RET_SINT16; break; case FFI_TYPE_UINT32: flags = UNIX64_RET_UINT32; break; case FFI_TYPE_INT: case FFI_TYPE_SINT32: flags = UNIX64_RET_SINT32; break; case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: flags = UNIX64_RET_INT64; break; case FFI_TYPE_POINTER: flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64); break; case FFI_TYPE_FLOAT: flags = UNIX64_RET_XMM32; break; case FFI_TYPE_DOUBLE: flags = UNIX64_RET_XMM64; break; #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: flags = UNIX64_RET_X87; break; #endif case FFI_TYPE_STRUCT: 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 = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM; } else { _Bool sse0 = SSE_CLASS_P (classes[0]); if (rtype_size == 4 && sse0) flags = UNIX64_RET_XMM32; else if (rtype_size == 8) flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64; else { _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); if (sse0 && sse1) flags = UNIX64_RET_ST_XMM0_XMM1; else if (sse0) flags = UNIX64_RET_ST_XMM0_RAX; else if (sse1) flags = UNIX64_RET_ST_RAX_XMM0; else flags = UNIX64_RET_ST_RAX_RDX; flags |= rtype_size << UNIX64_SIZE_SHIFT; } } break; case FFI_TYPE_COMPLEX: switch (rtype->elements[0]->type) { case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: case FFI_TYPE_INT: case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: flags = UNIX64_RET_ST_RAX_RDX | ((unsigned) rtype_size << UNIX64_SIZE_SHIFT); break; case FFI_TYPE_FLOAT: flags = UNIX64_RET_XMM64; break; case FFI_TYPE_DOUBLE: flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT); break; #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: flags = UNIX64_RET_X87_2; break; #endif default: return FFI_BAD_TYPEDEF; } break; default: return FFI_BAD_TYPEDEF; } /* 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 = FFI_ALIGN (bytes, align); bytes += cif->arg_types[i]->size; } else { gprcount += ngpr; ssecount += nsse; } } if (ssecount) flags |= UNIX64_FLAG_XMM_ARGS; cif->flags = flags; cif->bytes = (unsigned) FFI_ALIGN (bytes, 8); return FFI_OK; } static void ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { enum x86_64_reg_class classes[MAX_CLASSES]; char *stack, *argp; ffi_type **arg_types; int gprcount, ssecount, ngpr, nsse, i, avn, flags; struct register_args *reg_args; /* Can't call 32-bit mode from 64-bit mode. */ FFI_ASSERT (cif->abi == FFI_UNIX64); /* If the return value is a struct and we don't have a return value address then we need to make one. Otherwise we can ignore it. */ flags = cif->flags; if (rvalue == NULL) { if (flags & UNIX64_FLAG_RET_IN_MEM) rvalue = alloca (cif->rtype->size); else flags = UNIX64_RET_VOID; } /* Allocate the space for the arguments, plus 4 words of temp space. */ stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8); reg_args = (struct register_args *) stack; argp = stack + sizeof (struct register_args); reg_args->r10 = (uintptr_t) closure; gprcount = ssecount = 0; /* If the return value is passed in memory, add the pointer as the first integer argument. */ if (flags & UNIX64_FLAG_RET_IN_MEM) reg_args->gpr[gprcount++] = (unsigned long) rvalue; avn = cif->nargs; arg_types = cif->arg_types; for (i = 0; i < avn; ++i) { size_t n, size = arg_types[i]->size; 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 *) FFI_ALIGN (argp, align); memcpy (argp, avalue[i], size); argp += size; } else { /* The argument is passed entirely in registers. */ char *a = (char *) avalue[i]; unsigned int j; for (j = 0; j < n; j++, a += 8, size -= 8) { switch (classes[j]) { case X86_64_NO_CLASS: case X86_64_SSEUP_CLASS: break; case X86_64_INTEGER_CLASS: case X86_64_INTEGERSI_CLASS: /* Sign-extend integer arguments passed in general purpose registers, to cope with the fact that LLVM incorrectly assumes that this will be done (the x86-64 PS ABI does not specify this). */ switch (arg_types[i]->type) { case FFI_TYPE_SINT8: reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a); break; case FFI_TYPE_SINT16: reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a); break; case FFI_TYPE_SINT32: reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a); break; default: reg_args->gpr[gprcount] = 0; memcpy (®_args->gpr[gprcount], a, size); } gprcount++; break; case X86_64_SSE_CLASS: case X86_64_SSEDF_CLASS: memcpy (®_args->sse[ssecount++].i64, a, sizeof(UINT64)); break; case X86_64_SSESF_CLASS: memcpy (®_args->sse[ssecount++].i32, a, sizeof(UINT32)); break; default: abort(); } } } } reg_args->rax = ssecount; ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args), flags, rvalue, fn); } #ifndef __ILP32__ extern void ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); #endif void ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { #ifndef __ILP32__ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64) { ffi_call_efi64(cif, fn, rvalue, avalue); return; } #endif ffi_call_int (cif, fn, rvalue, avalue, NULL); } #ifndef __ILP32__ extern void ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure); #endif void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { #ifndef __ILP32__ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64) { ffi_call_go_efi64(cif, fn, rvalue, avalue, closure); return; } #endif ffi_call_int (cif, fn, rvalue, avalue, closure); } extern void ffi_closure_unix64(void) FFI_HIDDEN; extern void ffi_closure_unix64_sse(void) FFI_HIDDEN; #ifndef __ILP32__ extern ffi_status ffi_prep_closure_loc_efi64(ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, void *codeloc); #endif ffi_status ffi_prep_closure_loc (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, void *codeloc) { static const unsigned char trampoline[16] = { /* leaq -0x7(%rip),%r10 # 0x0 */ 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff, /* jmpq *0x3(%rip) # 0x10 */ 0xff, 0x25, 0x03, 0x00, 0x00, 0x00, /* nopl (%rax) */ 0x0f, 0x1f, 0x00 }; void (*dest)(void); char *tramp = closure->tramp; #ifndef __ILP32__ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64) return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc); #endif if (cif->abi != FFI_UNIX64) return FFI_BAD_ABI; if (cif->flags & UNIX64_FLAG_XMM_ARGS) dest = ffi_closure_unix64_sse; else dest = ffi_closure_unix64; memcpy (tramp, trampoline, sizeof(trampoline)); *(UINT64 *)(tramp + 16) = (uintptr_t)dest; closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK; } int FFI_HIDDEN ffi_closure_unix64_inner(ffi_cif *cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, void *rvalue, struct register_args *reg_args, char *argp) { void **avalue; ffi_type **arg_types; long i, avn; int gprcount, ssecount, ngpr, nsse; int flags; avn = cif->nargs; flags = cif->flags; avalue = alloca(avn * sizeof(void *)); gprcount = ssecount = 0; if (flags & UNIX64_FLAG_RET_IN_MEM) { /* On return, %rax will contain the address that was passed by the caller in %rdi. */ void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++]; *(void **)rvalue = r; rvalue = r; flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64); } arg_types = cif->arg_types; for (i = 0; i < avn; ++i) { enum x86_64_reg_class classes[MAX_CLASSES]; size_t 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 *) FFI_ALIGN (argp, align); avalue[i] = argp; argp += arg_types[i]->size; } /* If the argument is in a single register, or two consecutive integer registers, then we can use that address directly. */ else if (n == 1 || (n == 2 && !(SSE_CLASS_P (classes[0]) || SSE_CLASS_P (classes[1])))) { /* The argument is in a single register. */ if (SSE_CLASS_P (classes[0])) { avalue[i] = ®_args->sse[ssecount]; ssecount += n; } else { avalue[i] = ®_args->gpr[gprcount]; gprcount += n; } } /* Otherwise, allocate space to make them consecutive. */ else { char *a = alloca (16); unsigned 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. */ fun (cif, rvalue, avalue, user_data); /* Tell assembly how to perform return type promotions. */ return flags; } extern void ffi_go_closure_unix64(void) FFI_HIDDEN; extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN; #ifndef __ILP32__ extern ffi_status ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*)); #endif ffi_status ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*)) { #ifndef __ILP32__ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64) return ffi_prep_go_closure_efi64(closure, cif, fun); #endif if (cif->abi != FFI_UNIX64) return FFI_BAD_ABI; closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS ? ffi_go_closure_unix64_sse : ffi_go_closure_unix64); closure->cif = cif; closure->fun = fun; return FFI_OK; } #endif /* __x86_64__ */ ====================File: src/x86/ffitarget.h==================== /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */ FFI_LAST_ABI, #ifdef __GNUC__ FFI_DEFAULT_ABI = FFI_GNUW64 #else FFI_DEFAULT_ABI = FFI_WIN64 #endif #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_GNUW64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ====================File: src/x86/ffiw64.c==================== /* ----------------------------------------------------------------------- ffiw64.c - Copyright (c) 2018 Anthony Green Copyright (c) 2014 Red Hat, Inc. x86 win64 Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #if defined(__x86_64__) || defined(_M_AMD64) #include #include #include #include #ifdef X86_WIN64 #define EFI64(name) name #else #define EFI64(name) FFI_HIDDEN name##_efi64 #endif struct win64_call_frame { UINT64 rbp; /* 0 */ UINT64 retaddr; /* 8 */ UINT64 fn; /* 16 */ UINT64 flags; /* 24 */ UINT64 rvalue; /* 32 */ }; extern void ffi_call_win64 (void *stack, struct win64_call_frame *, void *closure) FFI_HIDDEN; ffi_status FFI_HIDDEN EFI64(ffi_prep_cif_machdep)(ffi_cif *cif) { int flags, n; switch (cif->abi) { case FFI_WIN64: case FFI_GNUW64: break; default: return FFI_BAD_ABI; } flags = cif->rtype->type; switch (flags) { default: break; case FFI_TYPE_LONGDOUBLE: /* GCC returns long double values by reference, like a struct */ if (cif->abi == FFI_GNUW64) flags = FFI_TYPE_STRUCT; break; case FFI_TYPE_COMPLEX: flags = FFI_TYPE_STRUCT; /* FALLTHRU */ case FFI_TYPE_STRUCT: switch (cif->rtype->size) { case 8: flags = FFI_TYPE_UINT64; break; case 4: flags = FFI_TYPE_SMALL_STRUCT_4B; break; case 2: flags = FFI_TYPE_SMALL_STRUCT_2B; break; case 1: flags = FFI_TYPE_SMALL_STRUCT_1B; break; } break; } cif->flags = flags; /* Each argument either fits in a register, an 8 byte slot, or is passed by reference with the pointer in the 8 byte slot. */ n = cif->nargs; n += (flags == FFI_TYPE_STRUCT); if (n < 4) n = 4; cif->bytes = n * 8; return FFI_OK; } static void ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { int i, j, n, flags; UINT64 *stack; size_t rsize; struct win64_call_frame *frame; FFI_ASSERT(cif->abi == FFI_GNUW64 || cif->abi == FFI_WIN64); flags = cif->flags; rsize = 0; /* If we have no return value for a structure, we need to create one. Otherwise we can ignore the return type entirely. */ if (rvalue == NULL) { if (flags == FFI_TYPE_STRUCT) rsize = cif->rtype->size; else flags = FFI_TYPE_VOID; } stack = alloca(cif->bytes + sizeof(struct win64_call_frame) + rsize); frame = (struct win64_call_frame *)((char *)stack + cif->bytes); if (rsize) rvalue = frame + 1; frame->fn = (uintptr_t)fn; frame->flags = flags; frame->rvalue = (uintptr_t)rvalue; j = 0; if (flags == FFI_TYPE_STRUCT) { stack[0] = (uintptr_t)rvalue; j = 1; } for (i = 0, n = cif->nargs; i < n; ++i, ++j) { switch (cif->arg_types[i]->size) { case 8: stack[j] = *(UINT64 *)avalue[i]; break; case 4: stack[j] = *(UINT32 *)avalue[i]; break; case 2: stack[j] = *(UINT16 *)avalue[i]; break; case 1: stack[j] = *(UINT8 *)avalue[i]; break; default: stack[j] = (uintptr_t)avalue[i]; break; } } ffi_call_win64 (stack, frame, closure); } void EFI64(ffi_call)(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { ffi_call_int (cif, fn, rvalue, avalue, NULL); } void EFI64(ffi_call_go)(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { ffi_call_int (cif, fn, rvalue, avalue, closure); } extern void ffi_closure_win64(void) FFI_HIDDEN; extern void ffi_go_closure_win64(void) FFI_HIDDEN; ffi_status EFI64(ffi_prep_closure_loc)(ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, void *codeloc) { static const unsigned char trampoline[16] = { /* leaq -0x7(%rip),%r10 # 0x0 */ 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff, /* jmpq *0x3(%rip) # 0x10 */ 0xff, 0x25, 0x03, 0x00, 0x00, 0x00, /* nopl (%rax) */ 0x0f, 0x1f, 0x00 }; char *tramp = closure->tramp; switch (cif->abi) { case FFI_WIN64: case FFI_GNUW64: break; default: return FFI_BAD_ABI; } memcpy (tramp, trampoline, sizeof(trampoline)); *(UINT64 *)(tramp + 16) = (uintptr_t)ffi_closure_win64; closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK; } ffi_status EFI64(ffi_prep_go_closure)(ffi_go_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*)) { switch (cif->abi) { case FFI_WIN64: case FFI_GNUW64: break; default: return FFI_BAD_ABI; } closure->tramp = ffi_go_closure_win64; closure->cif = cif; closure->fun = fun; return FFI_OK; } struct win64_closure_frame { UINT64 rvalue[2]; UINT64 fargs[4]; UINT64 retaddr; UINT64 args[]; }; /* Force the inner function to use the MS ABI. When compiling on win64 this is a nop. When compiling on unix, this simplifies the assembly, and places the burden of saving the extra call-saved registers on the compiler. */ int FFI_HIDDEN __attribute__((ms_abi)) ffi_closure_win64_inner(ffi_cif *cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, struct win64_closure_frame *frame) { void **avalue; void *rvalue; int i, n, nreg, flags; avalue = alloca(cif->nargs * sizeof(void *)); rvalue = frame->rvalue; nreg = 0; /* When returning a structure, the address is in the first argument. We must also be prepared to return the same address in eax, so install that address in the frame and pretend we return a pointer. */ flags = cif->flags; if (flags == FFI_TYPE_STRUCT) { rvalue = (void *)(uintptr_t)frame->args[0]; frame->rvalue[0] = frame->args[0]; nreg = 1; } for (i = 0, n = cif->nargs; i < n; ++i, ++nreg) { size_t size = cif->arg_types[i]->size; size_t type = cif->arg_types[i]->type; void *a; if (type == FFI_TYPE_DOUBLE || type == FFI_TYPE_FLOAT) { if (nreg < 4) a = &frame->fargs[nreg]; else a = &frame->args[nreg]; } else if (size == 1 || size == 2 || size == 4 || size == 8) a = &frame->args[nreg]; else a = (void *)(uintptr_t)frame->args[nreg]; avalue[i] = a; } /* Invoke the closure. */ fun (cif, rvalue, avalue, user_data); return flags; } #endif /* __x86_64__ */ ====================File: src/x86/sysv.S==================== /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 2017 Anthony Green - Copyright (c) 2013 The Written Word, Inc. - Copyright (c) 1996,1998,2001-2003,2005,2008,2010 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 THE AUTHORS OR COPYRIGHT HOLDERS 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 __i386__ #ifndef _MSC_VER #define LIBFFI_ASM #include #include #include "internal.h" #define C2(X, Y) X ## Y #define C1(X, Y) C2(X, Y) #ifdef __USER_LABEL_PREFIX__ # define C(X) C1(__USER_LABEL_PREFIX__, X) #else # define C(X) X #endif #ifdef X86_DARWIN # define L(X) C1(L, X) #else # define L(X) C1(.L, X) #endif #ifdef __ELF__ # define ENDF(X) .type X,@function; .size X, . - X #else # define ENDF(X) #endif /* Handle win32 fastcall name mangling. */ #ifdef X86_WIN32 # define ffi_call_i386 @ffi_call_i386@8 # define ffi_closure_inner @ffi_closure_inner@8 #else # define ffi_call_i386 C(ffi_call_i386) # define ffi_closure_inner C(ffi_closure_inner) #endif /* This macro allows the safe creation of jump tables without an actual table. The entry points into the table are all 8 bytes. The use of ORG asserts that we're at the correct location. */ /* ??? The clang assembler doesn't handle .org with symbolic expressions. */ #if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__)) # define E(BASE, X) .balign 8 #else # define E(BASE, X) .balign 8; .org BASE + X * 8 #endif .text .balign 16 .globl ffi_call_i386 FFI_HIDDEN(ffi_call_i386) /* This is declared as void ffi_call_i386(struct call_frame *frame, char *argp) __attribute__((fastcall)); Thus the arguments are present in ecx: frame edx: argp */ ffi_call_i386: L(UW0): # cfi_startproc #if !HAVE_FASTCALL movl 4(%esp), %ecx movl 8(%esp), %edx #endif movl (%esp), %eax /* move the return address */ movl %ebp, (%ecx) /* store %ebp into local frame */ movl %eax, 4(%ecx) /* store retaddr into local frame */ /* New stack frame based off ebp. 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-4, so from the perspective of the unwind info, it hasn't moved. */ movl %ecx, %ebp L(UW1): # cfi_def_cfa(%ebp, 8) # cfi_rel_offset(%ebp, 0) movl %edx, %esp /* set outgoing argument stack */ movl 20+R_EAX*4(%ebp), %eax /* set register arguments */ movl 20+R_EDX*4(%ebp), %edx movl 20+R_ECX*4(%ebp), %ecx call *8(%ebp) movl 12(%ebp), %ecx /* load return type code */ movl %ebx, 8(%ebp) /* preserve %ebx */ L(UW2): # cfi_rel_offset(%ebx, 8) andl $X86_RET_TYPE_MASK, %ecx #ifdef __PIC__ call C(__x86.get_pc_thunk.bx) L(pc1): leal L(store_table)-L(pc1)(%ebx, %ecx, 8), %ebx #else leal L(store_table)(,%ecx, 8), %ebx #endif movl 16(%ebp), %ecx /* load result address */ jmp *%ebx .balign 8 L(store_table): E(L(store_table), X86_RET_FLOAT) fstps (%ecx) jmp L(e1) E(L(store_table), X86_RET_DOUBLE) fstpl (%ecx) jmp L(e1) E(L(store_table), X86_RET_LDOUBLE) fstpt (%ecx) jmp L(e1) E(L(store_table), X86_RET_SINT8) movsbl %al, %eax mov %eax, (%ecx) jmp L(e1) E(L(store_table), X86_RET_SINT16) movswl %ax, %eax mov %eax, (%ecx) jmp L(e1) E(L(store_table), X86_RET_UINT8) movzbl %al, %eax mov %eax, (%ecx) jmp L(e1) E(L(store_table), X86_RET_UINT16) movzwl %ax, %eax mov %eax, (%ecx) jmp L(e1) E(L(store_table), X86_RET_INT64) movl %edx, 4(%ecx) /* fallthru */ E(L(store_table), X86_RET_INT32) movl %eax, (%ecx) /* fallthru */ E(L(store_table), X86_RET_VOID) L(e1): movl 8(%ebp), %ebx movl %ebp, %esp popl %ebp L(UW3): # cfi_remember_state # cfi_def_cfa(%esp, 4) # cfi_restore(%ebx) # cfi_restore(%ebp) ret L(UW4): # cfi_restore_state E(L(store_table), X86_RET_STRUCTPOP) jmp L(e1) E(L(store_table), X86_RET_STRUCTARG) jmp L(e1) E(L(store_table), X86_RET_STRUCT_1B) movb %al, (%ecx) jmp L(e1) E(L(store_table), X86_RET_STRUCT_2B) movw %ax, (%ecx) jmp L(e1) /* Fill out the table so that bad values are predictable. */ E(L(store_table), X86_RET_UNUSED14) ud2 E(L(store_table), X86_RET_UNUSED15) ud2 L(UW5): # cfi_endproc ENDF(ffi_call_i386) /* The inner helper is declared as void ffi_closure_inner(struct closure_frame *frame, char *argp) __attribute_((fastcall)) Thus the arguments are placed in ecx: frame edx: argp */ /* Macros to help setting up the closure_data structure. */ #if HAVE_FASTCALL # define closure_FS (40 + 4) # define closure_CF 0 #else # define closure_FS (8 + 40 + 12) # define closure_CF 8 #endif #define FFI_CLOSURE_SAVE_REGS \ movl %eax, closure_CF+16+R_EAX*4(%esp); \ movl %edx, closure_CF+16+R_EDX*4(%esp); \ movl %ecx, closure_CF+16+R_ECX*4(%esp) #define FFI_CLOSURE_COPY_TRAMP_DATA \ movl FFI_TRAMPOLINE_SIZE(%eax), %edx; /* copy cif */ \ movl FFI_TRAMPOLINE_SIZE+4(%eax), %ecx; /* copy fun */ \ movl FFI_TRAMPOLINE_SIZE+8(%eax), %eax; /* copy user_data */ \ movl %edx, closure_CF+28(%esp); \ movl %ecx, closure_CF+32(%esp); \ movl %eax, closure_CF+36(%esp) #if HAVE_FASTCALL # define FFI_CLOSURE_PREP_CALL \ movl %esp, %ecx; /* load closure_data */ \ leal closure_FS+4(%esp), %edx; /* load incoming stack */ #else # define FFI_CLOSURE_PREP_CALL \ leal closure_CF(%esp), %ecx; /* load closure_data */ \ leal closure_FS+4(%esp), %edx; /* load incoming stack */ \ movl %ecx, (%esp); \ movl %edx, 4(%esp) #endif #define FFI_CLOSURE_CALL_INNER(UWN) \ call ffi_closure_inner #define FFI_CLOSURE_MASK_AND_JUMP(N, UW) \ andl $X86_RET_TYPE_MASK, %eax; \ leal L(C1(load_table,N))(, %eax, 8), %edx; \ movl closure_CF(%esp), %eax; /* optimiztic load */ \ jmp *%edx #ifdef __PIC__ # if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE # undef FFI_CLOSURE_MASK_AND_JUMP # define FFI_CLOSURE_MASK_AND_JUMP(N, UW) \ andl $X86_RET_TYPE_MASK, %eax; \ call C(__x86.get_pc_thunk.dx); \ L(C1(pc,N)): \ leal L(C1(load_table,N))-L(C1(pc,N))(%edx, %eax, 8), %edx; \ movl closure_CF(%esp), %eax; /* optimiztic load */ \ jmp *%edx # else # define FFI_CLOSURE_CALL_INNER_SAVE_EBX # undef FFI_CLOSURE_CALL_INNER # define FFI_CLOSURE_CALL_INNER(UWN) \ movl %ebx, 40(%esp); /* save ebx */ \ L(C1(UW,UWN)): \ /* cfi_rel_offset(%ebx, 40); */ \ call C(__x86.get_pc_thunk.bx); /* load got register */ \ addl $C(_GLOBAL_OFFSET_TABLE_), %ebx; \ call ffi_closure_inner@PLT # undef FFI_CLOSURE_MASK_AND_JUMP # define FFI_CLOSURE_MASK_AND_JUMP(N, UWN) \ andl $X86_RET_TYPE_MASK, %eax; \ leal L(C1(load_table,N))@GOTOFF(%ebx, %eax, 8), %edx; \ movl 40(%esp), %ebx; /* restore ebx */ \ L(C1(UW,UWN)): \ /* cfi_restore(%ebx); */ \ movl closure_CF(%esp), %eax; /* optimiztic load */ \ jmp *%edx # endif /* DARWIN || HIDDEN */ #endif /* __PIC__ */ .balign 16 .globl C(ffi_go_closure_EAX) FFI_HIDDEN(C(ffi_go_closure_EAX)) C(ffi_go_closure_EAX): L(UW6): # cfi_startproc subl $closure_FS, %esp L(UW7): # cfi_def_cfa_offset(closure_FS + 4) FFI_CLOSURE_SAVE_REGS movl 4(%eax), %edx /* copy cif */ movl 8(%eax), %ecx /* copy fun */ movl %edx, closure_CF+28(%esp) movl %ecx, closure_CF+32(%esp) movl %eax, closure_CF+36(%esp) /* closure is user_data */ jmp L(do_closure_i386) L(UW8): # cfi_endproc ENDF(C(ffi_go_closure_EAX)) .balign 16 .globl C(ffi_go_closure_ECX) FFI_HIDDEN(C(ffi_go_closure_ECX)) C(ffi_go_closure_ECX): L(UW9): # cfi_startproc subl $closure_FS, %esp L(UW10): # cfi_def_cfa_offset(closure_FS + 4) FFI_CLOSURE_SAVE_REGS movl 4(%ecx), %edx /* copy cif */ movl 8(%ecx), %eax /* copy fun */ movl %edx, closure_CF+28(%esp) movl %eax, closure_CF+32(%esp) movl %ecx, closure_CF+36(%esp) /* closure is user_data */ jmp L(do_closure_i386) L(UW11): # cfi_endproc ENDF(C(ffi_go_closure_ECX)) /* The closure entry points are reached from the ffi_closure trampoline. On entry, %eax contains the address of the ffi_closure. */ .balign 16 .globl C(ffi_closure_i386) FFI_HIDDEN(C(ffi_closure_i386)) C(ffi_closure_i386): L(UW12): # cfi_startproc subl $closure_FS, %esp L(UW13): # cfi_def_cfa_offset(closure_FS + 4) FFI_CLOSURE_SAVE_REGS FFI_CLOSURE_COPY_TRAMP_DATA /* Entry point from preceeding Go closures. */ L(do_closure_i386): FFI_CLOSURE_PREP_CALL FFI_CLOSURE_CALL_INNER(14) FFI_CLOSURE_MASK_AND_JUMP(2, 15) .balign 8 L(load_table2): E(L(load_table2), X86_RET_FLOAT) flds closure_CF(%esp) jmp L(e2) E(L(load_table2), X86_RET_DOUBLE) fldl closure_CF(%esp) jmp L(e2) E(L(load_table2), X86_RET_LDOUBLE) fldt closure_CF(%esp) jmp L(e2) E(L(load_table2), X86_RET_SINT8) movsbl %al, %eax jmp L(e2) E(L(load_table2), X86_RET_SINT16) movswl %ax, %eax jmp L(e2) E(L(load_table2), X86_RET_UINT8) movzbl %al, %eax jmp L(e2) E(L(load_table2), X86_RET_UINT16) movzwl %ax, %eax jmp L(e2) E(L(load_table2), X86_RET_INT64) movl closure_CF+4(%esp), %edx jmp L(e2) E(L(load_table2), X86_RET_INT32) nop /* fallthru */ E(L(load_table2), X86_RET_VOID) L(e2): addl $closure_FS, %esp L(UW16): # cfi_adjust_cfa_offset(-closure_FS) ret L(UW17): # cfi_adjust_cfa_offset(closure_FS) E(L(load_table2), X86_RET_STRUCTPOP) addl $closure_FS, %esp L(UW18): # cfi_adjust_cfa_offset(-closure_FS) ret $4 L(UW19): # cfi_adjust_cfa_offset(closure_FS) E(L(load_table2), X86_RET_STRUCTARG) jmp L(e2) E(L(load_table2), X86_RET_STRUCT_1B) movzbl %al, %eax jmp L(e2) E(L(load_table2), X86_RET_STRUCT_2B) movzwl %ax, %eax jmp L(e2) /* Fill out the table so that bad values are predictable. */ E(L(load_table2), X86_RET_UNUSED14) ud2 E(L(load_table2), X86_RET_UNUSED15) ud2 L(UW20): # cfi_endproc ENDF(C(ffi_closure_i386)) .balign 16 .globl C(ffi_go_closure_STDCALL) FFI_HIDDEN(C(ffi_go_closure_STDCALL)) C(ffi_go_closure_STDCALL): L(UW21): # cfi_startproc subl $closure_FS, %esp L(UW22): # cfi_def_cfa_offset(closure_FS + 4) FFI_CLOSURE_SAVE_REGS movl 4(%ecx), %edx /* copy cif */ movl 8(%ecx), %eax /* copy fun */ movl %edx, closure_CF+28(%esp) movl %eax, closure_CF+32(%esp) movl %ecx, closure_CF+36(%esp) /* closure is user_data */ jmp L(do_closure_STDCALL) L(UW23): # cfi_endproc ENDF(C(ffi_go_closure_STDCALL)) /* For REGISTER, we have no available parameter registers, and so we enter here having pushed the closure onto the stack. */ .balign 16 .globl C(ffi_closure_REGISTER) FFI_HIDDEN(C(ffi_closure_REGISTER)) C(ffi_closure_REGISTER): L(UW24): # cfi_startproc # cfi_def_cfa(%esp, 8) # cfi_offset(%eip, -8) subl $closure_FS-4, %esp L(UW25): # cfi_def_cfa_offset(closure_FS + 4) FFI_CLOSURE_SAVE_REGS movl closure_FS-4(%esp), %ecx /* load retaddr */ movl closure_FS(%esp), %eax /* load closure */ movl %ecx, closure_FS(%esp) /* move retaddr */ jmp L(do_closure_REGISTER) L(UW26): # cfi_endproc ENDF(C(ffi_closure_REGISTER)) /* For STDCALL (and others), we need to pop N bytes of arguments off the stack following the closure. The amount needing to be popped is returned to us from ffi_closure_inner. */ .balign 16 .globl C(ffi_closure_STDCALL) FFI_HIDDEN(C(ffi_closure_STDCALL)) C(ffi_closure_STDCALL): L(UW27): # cfi_startproc subl $closure_FS, %esp L(UW28): # cfi_def_cfa_offset(closure_FS + 4) FFI_CLOSURE_SAVE_REGS /* Entry point from ffi_closure_REGISTER. */ L(do_closure_REGISTER): FFI_CLOSURE_COPY_TRAMP_DATA /* Entry point from preceeding Go closure. */ L(do_closure_STDCALL): FFI_CLOSURE_PREP_CALL FFI_CLOSURE_CALL_INNER(29) movl %eax, %ecx shrl $X86_RET_POP_SHIFT, %ecx /* isolate pop count */ leal closure_FS(%esp, %ecx), %ecx /* compute popped esp */ movl closure_FS(%esp), %edx /* move return address */ movl %edx, (%ecx) /* From this point on, the value of %esp upon return is %ecx+4, and we've copied the return address to %ecx to make return easy. There's no point in representing this in the unwind info, as there is always a window between the mov and the ret which will be wrong from one point of view or another. */ FFI_CLOSURE_MASK_AND_JUMP(3, 30) .balign 8 L(load_table3): E(L(load_table3), X86_RET_FLOAT) flds closure_CF(%esp) movl %ecx, %esp ret E(L(load_table3), X86_RET_DOUBLE) fldl closure_CF(%esp) movl %ecx, %esp ret E(L(load_table3), X86_RET_LDOUBLE) fldt closure_CF(%esp) movl %ecx, %esp ret E(L(load_table3), X86_RET_SINT8) movsbl %al, %eax movl %ecx, %esp ret E(L(load_table3), X86_RET_SINT16) movswl %ax, %eax movl %ecx, %esp ret E(L(load_table3), X86_RET_UINT8) movzbl %al, %eax movl %ecx, %esp ret E(L(load_table3), X86_RET_UINT16) movzwl %ax, %eax movl %ecx, %esp ret E(L(load_table3), X86_RET_INT64) movl closure_CF+4(%esp), %edx movl %ecx, %esp ret E(L(load_table3), X86_RET_INT32) movl %ecx, %esp ret E(L(load_table3), X86_RET_VOID) movl %ecx, %esp ret E(L(load_table3), X86_RET_STRUCTPOP) movl %ecx, %esp ret E(L(load_table3), X86_RET_STRUCTARG) movl %ecx, %esp ret E(L(load_table3), X86_RET_STRUCT_1B) movzbl %al, %eax movl %ecx, %esp ret E(L(load_table3), X86_RET_STRUCT_2B) movzwl %ax, %eax movl %ecx, %esp ret /* Fill out the table so that bad values are predictable. */ E(L(load_table3), X86_RET_UNUSED14) ud2 E(L(load_table3), X86_RET_UNUSED15) ud2 L(UW31): # cfi_endproc ENDF(C(ffi_closure_STDCALL)) #if !FFI_NO_RAW_API #define raw_closure_S_FS (16+16+12) .balign 16 .globl C(ffi_closure_raw_SYSV) FFI_HIDDEN(C(ffi_closure_raw_SYSV)) C(ffi_closure_raw_SYSV): L(UW32): # cfi_startproc subl $raw_closure_S_FS, %esp L(UW33): # cfi_def_cfa_offset(raw_closure_S_FS + 4) movl %ebx, raw_closure_S_FS-4(%esp) L(UW34): # cfi_rel_offset(%ebx, raw_closure_S_FS-4) movl FFI_TRAMPOLINE_SIZE+8(%eax), %edx /* load cl->user_data */ movl %edx, 12(%esp) leal raw_closure_S_FS+4(%esp), %edx /* load raw_args */ movl %edx, 8(%esp) leal 16(%esp), %edx /* load &res */ movl %edx, 4(%esp) movl FFI_TRAMPOLINE_SIZE(%eax), %ebx /* load cl->cif */ movl %ebx, (%esp) call *FFI_TRAMPOLINE_SIZE+4(%eax) /* call cl->fun */ movl 20(%ebx), %eax /* load cif->flags */ andl $X86_RET_TYPE_MASK, %eax #ifdef __PIC__ call C(__x86.get_pc_thunk.bx) L(pc4): leal L(load_table4)-L(pc4)(%ebx, %eax, 8), %ecx #else leal L(load_table4)(,%eax, 8), %ecx #endif movl raw_closure_S_FS-4(%esp), %ebx L(UW35): # cfi_restore(%ebx) movl 16(%esp), %eax /* Optimistic load */ jmp *%ecx .balign 8 L(load_table4): E(L(load_table4), X86_RET_FLOAT) flds 16(%esp) jmp L(e4) E(L(load_table4), X86_RET_DOUBLE) fldl 16(%esp) jmp L(e4) E(L(load_table4), X86_RET_LDOUBLE) fldt 16(%esp) jmp L(e4) E(L(load_table4), X86_RET_SINT8) movsbl %al, %eax jmp L(e4) E(L(load_table4), X86_RET_SINT16) movswl %ax, %eax jmp L(e4) E(L(load_table4), X86_RET_UINT8) movzbl %al, %eax jmp L(e4) E(L(load_table4), X86_RET_UINT16) movzwl %ax, %eax jmp L(e4) E(L(load_table4), X86_RET_INT64) movl 16+4(%esp), %edx jmp L(e4) E(L(load_table4), X86_RET_INT32) nop /* fallthru */ E(L(load_table4), X86_RET_VOID) L(e4): addl $raw_closure_S_FS, %esp L(UW36): # cfi_adjust_cfa_offset(-raw_closure_S_FS) ret L(UW37): # cfi_adjust_cfa_offset(raw_closure_S_FS) E(L(load_table4), X86_RET_STRUCTPOP) addl $raw_closure_S_FS, %esp L(UW38): # cfi_adjust_cfa_offset(-raw_closure_S_FS) ret $4 L(UW39): # cfi_adjust_cfa_offset(raw_closure_S_FS) E(L(load_table4), X86_RET_STRUCTARG) jmp L(e4) E(L(load_table4), X86_RET_STRUCT_1B) movzbl %al, %eax jmp L(e4) E(L(load_table4), X86_RET_STRUCT_2B) movzwl %ax, %eax jmp L(e4) /* Fill out the table so that bad values are predictable. */ E(L(load_table4), X86_RET_UNUSED14) ud2 E(L(load_table4), X86_RET_UNUSED15) ud2 L(UW40): # cfi_endproc ENDF(C(ffi_closure_raw_SYSV)) #define raw_closure_T_FS (16+16+8) .balign 16 .globl C(ffi_closure_raw_THISCALL) FFI_HIDDEN(C(ffi_closure_raw_THISCALL)) C(ffi_closure_raw_THISCALL): L(UW41): # cfi_startproc /* Rearrange the stack such that %ecx is the first argument. This means moving the return address. */ popl %edx L(UW42): # cfi_def_cfa_offset(0) # cfi_register(%eip, %edx) pushl %ecx L(UW43): # cfi_adjust_cfa_offset(4) pushl %edx L(UW44): # cfi_adjust_cfa_offset(4) # cfi_rel_offset(%eip, 0) subl $raw_closure_T_FS, %esp L(UW45): # cfi_adjust_cfa_offset(raw_closure_T_FS) movl %ebx, raw_closure_T_FS-4(%esp) L(UW46): # cfi_rel_offset(%ebx, raw_closure_T_FS-4) movl FFI_TRAMPOLINE_SIZE+8(%eax), %edx /* load cl->user_data */ movl %edx, 12(%esp) leal raw_closure_T_FS+4(%esp), %edx /* load raw_args */ movl %edx, 8(%esp) leal 16(%esp), %edx /* load &res */ movl %edx, 4(%esp) movl FFI_TRAMPOLINE_SIZE(%eax), %ebx /* load cl->cif */ movl %ebx, (%esp) call *FFI_TRAMPOLINE_SIZE+4(%eax) /* call cl->fun */ movl 20(%ebx), %eax /* load cif->flags */ andl $X86_RET_TYPE_MASK, %eax #ifdef __PIC__ call C(__x86.get_pc_thunk.bx) L(pc5): leal L(load_table5)-L(pc5)(%ebx, %eax, 8), %ecx #else leal L(load_table5)(,%eax, 8), %ecx #endif movl raw_closure_T_FS-4(%esp), %ebx L(UW47): # cfi_restore(%ebx) movl 16(%esp), %eax /* Optimistic load */ jmp *%ecx .balign 8 L(load_table5): E(L(load_table5), X86_RET_FLOAT) flds 16(%esp) jmp L(e5) E(L(load_table5), X86_RET_DOUBLE) fldl 16(%esp) jmp L(e5) E(L(load_table5), X86_RET_LDOUBLE) fldt 16(%esp) jmp L(e5) E(L(load_table5), X86_RET_SINT8) movsbl %al, %eax jmp L(e5) E(L(load_table5), X86_RET_SINT16) movswl %ax, %eax jmp L(e5) E(L(load_table5), X86_RET_UINT8) movzbl %al, %eax jmp L(e5) E(L(load_table5), X86_RET_UINT16) movzwl %ax, %eax jmp L(e5) E(L(load_table5), X86_RET_INT64) movl 16+4(%esp), %edx jmp L(e5) E(L(load_table5), X86_RET_INT32) nop /* fallthru */ E(L(load_table5), X86_RET_VOID) L(e5): addl $raw_closure_T_FS, %esp L(UW48): # cfi_adjust_cfa_offset(-raw_closure_T_FS) /* Remove the extra %ecx argument we pushed. */ ret $4 L(UW49): # cfi_adjust_cfa_offset(raw_closure_T_FS) E(L(load_table5), X86_RET_STRUCTPOP) addl $raw_closure_T_FS, %esp L(UW50): # cfi_adjust_cfa_offset(-raw_closure_T_FS) ret $8 L(UW51): # cfi_adjust_cfa_offset(raw_closure_T_FS) E(L(load_table5), X86_RET_STRUCTARG) jmp L(e5) E(L(load_table5), X86_RET_STRUCT_1B) movzbl %al, %eax jmp L(e5) E(L(load_table5), X86_RET_STRUCT_2B) movzwl %ax, %eax jmp L(e5) /* Fill out the table so that bad values are predictable. */ E(L(load_table5), X86_RET_UNUSED14) ud2 E(L(load_table5), X86_RET_UNUSED15) ud2 L(UW52): # cfi_endproc ENDF(C(ffi_closure_raw_THISCALL)) #endif /* !FFI_NO_RAW_API */ #ifdef X86_DARWIN # define COMDAT(X) \ .section __TEXT,__text,coalesced,pure_instructions; \ .weak_definition X; \ FFI_HIDDEN(X) #elif defined __ELF__ && !(defined(__sun__) && defined(__svr4__)) # define COMDAT(X) \ .section .text.X,"axG",@progbits,X,comdat; \ .globl X; \ FFI_HIDDEN(X) #else # define COMDAT(X) #endif #if defined(__PIC__) COMDAT(C(__x86.get_pc_thunk.bx)) C(__x86.get_pc_thunk.bx): movl (%esp), %ebx ret ENDF(C(__x86.get_pc_thunk.bx)) # if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE COMDAT(C(__x86.get_pc_thunk.dx)) C(__x86.get_pc_thunk.dx): movl (%esp), %edx ret ENDF(C(__x86.get_pc_thunk.dx)) #endif /* DARWIN || HIDDEN */ #endif /* __PIC__ */ /* Sadly, OSX cctools-as doesn't understand .cfi directives at all. */ #ifdef __APPLE__ .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support EHFrame0: #elif defined(X86_WIN32) .section .eh_frame,"r" #elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE) .section .eh_frame,EH_FRAME_FLAGS,@unwind #else .section .eh_frame,EH_FRAME_FLAGS,@progbits #endif #ifdef HAVE_AS_X86_PCREL # define PCREL(X) X - . #else # define PCREL(X) X@rel #endif /* Simplify advancing between labels. Assume DW_CFA_advance_loc1 fits. */ #define ADV(N, P) .byte 2, L(N)-L(P) .balign 4 L(CIE): .set L(set0),L(ECIE)-L(SCIE) .long L(set0) /* CIE Length */ L(SCIE): .long 0 /* CIE Identifier Tag */ .byte 1 /* CIE Version */ .ascii "zR\0" /* CIE Augmentation */ .byte 1 /* CIE Code Alignment Factor */ .byte 0x7c /* CIE Data Alignment Factor */ .byte 0x8 /* CIE RA Column */ .byte 1 /* Augmentation size */ .byte 0x1b /* FDE Encoding (pcrel sdata4) */ .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp offset 4 */ .byte 0x80+8, 1 /* DW_CFA_offset, %eip offset 1*-4 */ .balign 4 L(ECIE): .set L(set1),L(EFDE1)-L(SFDE1) .long L(set1) /* FDE Length */ L(SFDE1): .long L(SFDE1)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW0)) /* Initial location */ .long L(UW5)-L(UW0) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW1, UW0) .byte 0xc, 5, 8 /* DW_CFA_def_cfa, %ebp 8 */ .byte 0x80+5, 2 /* DW_CFA_offset, %ebp 2*-4 */ ADV(UW2, UW1) .byte 0x80+3, 0 /* DW_CFA_offset, %ebx 0*-4 */ ADV(UW3, UW2) .byte 0xa /* DW_CFA_remember_state */ .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp 4 */ .byte 0xc0+3 /* DW_CFA_restore, %ebx */ .byte 0xc0+5 /* DW_CFA_restore, %ebp */ ADV(UW4, UW3) .byte 0xb /* DW_CFA_restore_state */ .balign 4 L(EFDE1): .set L(set2),L(EFDE2)-L(SFDE2) .long L(set2) /* FDE Length */ L(SFDE2): .long L(SFDE2)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW6)) /* Initial location */ .long L(UW8)-L(UW6) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW7, UW6) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ .balign 4 L(EFDE2): .set L(set3),L(EFDE3)-L(SFDE3) .long L(set3) /* FDE Length */ L(SFDE3): .long L(SFDE3)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW9)) /* Initial location */ .long L(UW11)-L(UW9) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW10, UW9) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ .balign 4 L(EFDE3): .set L(set4),L(EFDE4)-L(SFDE4) .long L(set4) /* FDE Length */ L(SFDE4): .long L(SFDE4)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW12)) /* Initial location */ .long L(UW20)-L(UW12) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW13, UW12) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ #ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX ADV(UW14, UW13) .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */ ADV(UW15, UW14) .byte 0xc0+3 /* DW_CFA_restore %ebx */ ADV(UW16, UW15) #else ADV(UW16, UW13) #endif .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ ADV(UW17, UW16) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ ADV(UW18, UW17) .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ ADV(UW19, UW18) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ .balign 4 L(EFDE4): .set L(set5),L(EFDE5)-L(SFDE5) .long L(set5) /* FDE Length */ L(SFDE5): .long L(SFDE5)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW21)) /* Initial location */ .long L(UW23)-L(UW21) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW22, UW21) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ .balign 4 L(EFDE5): .set L(set6),L(EFDE6)-L(SFDE6) .long L(set6) /* FDE Length */ L(SFDE6): .long L(SFDE6)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW24)) /* Initial location */ .long L(UW26)-L(UW24) /* Address range */ .byte 0 /* Augmentation size */ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ .byte 0x80+8, 2 /* DW_CFA_offset %eip, 2*-4 */ ADV(UW25, UW24) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ .balign 4 L(EFDE6): .set L(set7),L(EFDE7)-L(SFDE7) .long L(set7) /* FDE Length */ L(SFDE7): .long L(SFDE7)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW27)) /* Initial location */ .long L(UW31)-L(UW27) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW28, UW27) .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ #ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX ADV(UW29, UW28) .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */ ADV(UW30, UW29) .byte 0xc0+3 /* DW_CFA_restore %ebx */ #endif .balign 4 L(EFDE7): #if !FFI_NO_RAW_API .set L(set8),L(EFDE8)-L(SFDE8) .long L(set8) /* FDE Length */ L(SFDE8): .long L(SFDE8)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW32)) /* Initial location */ .long L(UW40)-L(UW32) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW33, UW32) .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */ ADV(UW34, UW33) .byte 0x80+3, 2 /* DW_CFA_offset %ebx 2*-4 */ ADV(UW35, UW34) .byte 0xc0+3 /* DW_CFA_restore %ebx */ ADV(UW36, UW35) .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ ADV(UW37, UW36) .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */ ADV(UW38, UW37) .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ ADV(UW39, UW38) .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */ .balign 4 L(EFDE8): .set L(set9),L(EFDE9)-L(SFDE9) .long L(set9) /* FDE Length */ L(SFDE9): .long L(SFDE9)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW41)) /* Initial location */ .long L(UW52)-L(UW41) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW42, UW41) .byte 0xe, 0 /* DW_CFA_def_cfa_offset */ .byte 0x9, 8, 2 /* DW_CFA_register %eip, %edx */ ADV(UW43, UW42) .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ ADV(UW44, UW43) .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ .byte 0x80+8, 2 /* DW_CFA_offset %eip 2*-4 */ ADV(UW45, UW44) .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */ ADV(UW46, UW45) .byte 0x80+3, 3 /* DW_CFA_offset %ebx 3*-4 */ ADV(UW47, UW46) .byte 0xc0+3 /* DW_CFA_restore %ebx */ ADV(UW48, UW47) .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ ADV(UW49, UW48) .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */ ADV(UW50, UW49) .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ ADV(UW51, UW50) .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */ .balign 4 L(EFDE9): #endif /* !FFI_NO_RAW_API */ #ifdef _WIN32 .def @feat.00; .scl 3; .type 0; .endef .globl @feat.00 @feat.00 = 1 #endif #ifdef __APPLE__ .subsections_via_symbols .section __LD,__compact_unwind,regular,debug /* compact unwind for ffi_call_i386 */ .long C(ffi_call_i386) .set L1,L(UW5)-L(UW0) .long L1 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_go_closure_EAX */ .long C(ffi_go_closure_EAX) .set L2,L(UW8)-L(UW6) .long L2 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_go_closure_ECX */ .long C(ffi_go_closure_ECX) .set L3,L(UW11)-L(UW9) .long L3 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_closure_i386 */ .long C(ffi_closure_i386) .set L4,L(UW20)-L(UW12) .long L4 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_go_closure_STDCALL */ .long C(ffi_go_closure_STDCALL) .set L5,L(UW23)-L(UW21) .long L5 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_closure_REGISTER */ .long C(ffi_closure_REGISTER) .set L6,L(UW26)-L(UW24) .long L6 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_closure_STDCALL */ .long C(ffi_closure_STDCALL) .set L7,L(UW31)-L(UW27) .long L7 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_closure_raw_SYSV */ .long C(ffi_closure_raw_SYSV) .set L8,L(UW40)-L(UW32) .long L8 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 /* compact unwind for ffi_closure_raw_THISCALL */ .long C(ffi_closure_raw_THISCALL) .set L9,L(UW52)-L(UW41) .long L9 .long 0x04000000 /* use dwarf unwind info */ .long 0 .long 0 #endif /* __APPLE__ */ #endif /* ifndef _MSC_VER */ #endif /* ifdef __i386__ */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif ====================File: src/x86/unix64.S==================== /* ----------------------------------------------------------------------- unix64.S - Copyright (c) 2013 The Written Word, Inc. - Copyright (c) 2008 Red Hat, Inc - Copyright (c) 2002 Bo Thorsen 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 THE AUTHORS OR COPYRIGHT HOLDERS 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 #include #include "internal64.h" #include "asmnames.h" .text /* This macro allows the safe creation of jump tables without an actual table. The entry points into the table are all 8 bytes. The use of ORG asserts that we're at the correct location. */ /* ??? The clang assembler doesn't handle .org with symbolic expressions. */ #if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__)) # define E(BASE, X) .balign 8 #else # define E(BASE, X) .balign 8; .org BASE + X * 8 #endif /* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, void *raddr, void (*fnaddr)(void)); 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. */ .balign 8 .globl C(ffi_call_unix64) FFI_HIDDEN(C(ffi_call_unix64)) C(ffi_call_unix64): L(UW0): 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. */ /* 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. */ L(UW1): /* cfi_def_cfa(%rbp, 32) */ /* cfi_rel_offset(%rbp, 16) */ 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 0x08(%r10), %rsi movq 0x10(%r10), %rdx movq 0x18(%r10), %rcx movq 0x20(%r10), %r8 movq 0x28(%r10), %r9 movl 0xb0(%r10), %eax testl %eax, %eax jnz L(load_sse) L(ret_from_load_sse): /* Deallocate the reg arg area, except for r10, then load via pop. */ leaq 0xb8(%r10), %rsp popq %r10 /* 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. */ L(UW2): /* cfi_remember_state */ /* cfi_def_cfa(%rsp, 8) */ /* cfi_restore(%rbp) */ /* The first byte of the flags contains the FFI_TYPE. */ cmpb $UNIX64_RET_LAST, %cl movzbl %cl, %r10d leaq L(store_table)(%rip), %r11 ja L(sa) leaq (%r11, %r10, 8), %r10 /* Prep for the structure cases: scratch area in redzone. */ leaq -20(%rsp), %rsi jmp *%r10 .balign 8 L(store_table): E(L(store_table), UNIX64_RET_VOID) ret E(L(store_table), UNIX64_RET_UINT8) movzbl %al, %eax movq %rax, (%rdi) ret E(L(store_table), UNIX64_RET_UINT16) movzwl %ax, %eax movq %rax, (%rdi) ret E(L(store_table), UNIX64_RET_UINT32) movl %eax, %eax movq %rax, (%rdi) ret E(L(store_table), UNIX64_RET_SINT8) movsbq %al, %rax movq %rax, (%rdi) ret E(L(store_table), UNIX64_RET_SINT16) movswq %ax, %rax movq %rax, (%rdi) ret E(L(store_table), UNIX64_RET_SINT32) cltq movq %rax, (%rdi) ret E(L(store_table), UNIX64_RET_INT64) movq %rax, (%rdi) ret E(L(store_table), UNIX64_RET_XMM32) movd %xmm0, (%rdi) ret E(L(store_table), UNIX64_RET_XMM64) movq %xmm0, (%rdi) ret E(L(store_table), UNIX64_RET_X87) fstpt (%rdi) ret E(L(store_table), UNIX64_RET_X87_2) fstpt (%rdi) fstpt 16(%rdi) ret E(L(store_table), UNIX64_RET_ST_XMM0_RAX) movq %rax, 8(%rsi) jmp L(s3) E(L(store_table), UNIX64_RET_ST_RAX_XMM0) movq %xmm0, 8(%rsi) jmp L(s2) E(L(store_table), UNIX64_RET_ST_XMM0_XMM1) movq %xmm1, 8(%rsi) jmp L(s3) E(L(store_table), UNIX64_RET_ST_RAX_RDX) movq %rdx, 8(%rsi) L(s2): movq %rax, (%rsi) shrl $UNIX64_SIZE_SHIFT, %ecx rep movsb ret .balign 8 L(s3): movq %xmm0, (%rsi) shrl $UNIX64_SIZE_SHIFT, %ecx rep movsb ret L(sa): call PLT(C(abort)) /* 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. */ .balign 2 L(UW3): /* cfi_restore_state */ L(load_sse): movdqa 0x30(%r10), %xmm0 movdqa 0x40(%r10), %xmm1 movdqa 0x50(%r10), %xmm2 movdqa 0x60(%r10), %xmm3 movdqa 0x70(%r10), %xmm4 movdqa 0x80(%r10), %xmm5 movdqa 0x90(%r10), %xmm6 movdqa 0xa0(%r10), %xmm7 jmp L(ret_from_load_sse) L(UW4): ENDF(C(ffi_call_unix64)) /* 6 general registers, 8 vector registers, 32 bytes of rvalue, 8 bytes of alignment. */ #define ffi_closure_OFS_G 0 #define ffi_closure_OFS_V (6*8) #define ffi_closure_OFS_RVALUE (ffi_closure_OFS_V + 8*16) #define ffi_closure_FS (ffi_closure_OFS_RVALUE + 32 + 8) /* The location of rvalue within the red zone after deallocating the frame. */ #define ffi_closure_RED_RVALUE (ffi_closure_OFS_RVALUE - ffi_closure_FS) .balign 2 .globl C(ffi_closure_unix64_sse) FFI_HIDDEN(C(ffi_closure_unix64_sse)) C(ffi_closure_unix64_sse): L(UW5): subq $ffi_closure_FS, %rsp L(UW6): /* cfi_adjust_cfa_offset(ffi_closure_FS) */ movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp) movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp) movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp) movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp) movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp) movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp) movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp) movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp) jmp L(sse_entry1) L(UW7): ENDF(C(ffi_closure_unix64_sse)) .balign 2 .globl C(ffi_closure_unix64) FFI_HIDDEN(C(ffi_closure_unix64)) C(ffi_closure_unix64): L(UW8): subq $ffi_closure_FS, %rsp L(UW9): /* cfi_adjust_cfa_offset(ffi_closure_FS) */ L(sse_entry1): movq %rdi, ffi_closure_OFS_G+0x00(%rsp) movq %rsi, ffi_closure_OFS_G+0x08(%rsp) movq %rdx, ffi_closure_OFS_G+0x10(%rsp) movq %rcx, ffi_closure_OFS_G+0x18(%rsp) movq %r8, ffi_closure_OFS_G+0x20(%rsp) movq %r9, ffi_closure_OFS_G+0x28(%rsp) #ifdef __ILP32__ movl FFI_TRAMPOLINE_SIZE(%r10), %edi /* Load cif */ movl FFI_TRAMPOLINE_SIZE+4(%r10), %esi /* Load fun */ movl FFI_TRAMPOLINE_SIZE+8(%r10), %edx /* Load user_data */ #else movq FFI_TRAMPOLINE_SIZE(%r10), %rdi /* Load cif */ movq FFI_TRAMPOLINE_SIZE+8(%r10), %rsi /* Load fun */ movq FFI_TRAMPOLINE_SIZE+16(%r10), %rdx /* Load user_data */ #endif L(do_closure): leaq ffi_closure_OFS_RVALUE(%rsp), %rcx /* Load rvalue */ movq %rsp, %r8 /* Load reg_args */ leaq ffi_closure_FS+8(%rsp), %r9 /* Load argp */ call PLT(C(ffi_closure_unix64_inner)) /* Deallocate stack frame early; return value is now in redzone. */ addq $ffi_closure_FS, %rsp L(UW10): /* cfi_adjust_cfa_offset(-ffi_closure_FS) */ /* The first byte of the return value contains the FFI_TYPE. */ cmpb $UNIX64_RET_LAST, %al movzbl %al, %r10d leaq L(load_table)(%rip), %r11 ja L(la) leaq (%r11, %r10, 8), %r10 leaq ffi_closure_RED_RVALUE(%rsp), %rsi jmp *%r10 .balign 8 L(load_table): E(L(load_table), UNIX64_RET_VOID) ret E(L(load_table), UNIX64_RET_UINT8) movzbl (%rsi), %eax ret E(L(load_table), UNIX64_RET_UINT16) movzwl (%rsi), %eax ret E(L(load_table), UNIX64_RET_UINT32) movl (%rsi), %eax ret E(L(load_table), UNIX64_RET_SINT8) movsbl (%rsi), %eax ret E(L(load_table), UNIX64_RET_SINT16) movswl (%rsi), %eax ret E(L(load_table), UNIX64_RET_SINT32) movl (%rsi), %eax ret E(L(load_table), UNIX64_RET_INT64) movq (%rsi), %rax ret E(L(load_table), UNIX64_RET_XMM32) movd (%rsi), %xmm0 ret E(L(load_table), UNIX64_RET_XMM64) movq (%rsi), %xmm0 ret E(L(load_table), UNIX64_RET_X87) fldt (%rsi) ret E(L(load_table), UNIX64_RET_X87_2) fldt 16(%rsi) fldt (%rsi) ret E(L(load_table), UNIX64_RET_ST_XMM0_RAX) movq 8(%rsi), %rax jmp L(l3) E(L(load_table), UNIX64_RET_ST_RAX_XMM0) movq 8(%rsi), %xmm0 jmp L(l2) E(L(load_table), UNIX64_RET_ST_XMM0_XMM1) movq 8(%rsi), %xmm1 jmp L(l3) E(L(load_table), UNIX64_RET_ST_RAX_RDX) movq 8(%rsi), %rdx L(l2): movq (%rsi), %rax ret .balign 8 L(l3): movq (%rsi), %xmm0 ret L(la): call PLT(C(abort)) L(UW11): ENDF(C(ffi_closure_unix64)) .balign 2 .globl C(ffi_go_closure_unix64_sse) FFI_HIDDEN(C(ffi_go_closure_unix64_sse)) C(ffi_go_closure_unix64_sse): L(UW12): subq $ffi_closure_FS, %rsp L(UW13): /* cfi_adjust_cfa_offset(ffi_closure_FS) */ movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp) movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp) movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp) movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp) movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp) movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp) movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp) movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp) jmp L(sse_entry2) L(UW14): ENDF(C(ffi_go_closure_unix64_sse)) .balign 2 .globl C(ffi_go_closure_unix64) FFI_HIDDEN(C(ffi_go_closure_unix64)) C(ffi_go_closure_unix64): L(UW15): subq $ffi_closure_FS, %rsp L(UW16): /* cfi_adjust_cfa_offset(ffi_closure_FS) */ L(sse_entry2): movq %rdi, ffi_closure_OFS_G+0x00(%rsp) movq %rsi, ffi_closure_OFS_G+0x08(%rsp) movq %rdx, ffi_closure_OFS_G+0x10(%rsp) movq %rcx, ffi_closure_OFS_G+0x18(%rsp) movq %r8, ffi_closure_OFS_G+0x20(%rsp) movq %r9, ffi_closure_OFS_G+0x28(%rsp) #ifdef __ILP32__ movl 4(%r10), %edi /* Load cif */ movl 8(%r10), %esi /* Load fun */ movl %r10d, %edx /* Load closure (user_data) */ #else movq 8(%r10), %rdi /* Load cif */ movq 16(%r10), %rsi /* Load fun */ movq %r10, %rdx /* Load closure (user_data) */ #endif jmp L(do_closure) L(UW17): ENDF(C(ffi_go_closure_unix64)) /* Sadly, OSX cctools-as doesn't understand .cfi directives at all. */ #ifdef __APPLE__ .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support EHFrame0: #elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE) .section .eh_frame,"a",@unwind #else .section .eh_frame,"a",@progbits #endif #ifdef HAVE_AS_X86_PCREL # define PCREL(X) X - . #else # define PCREL(X) X@rel #endif /* Simplify advancing between labels. Assume DW_CFA_advance_loc1 fits. */ #define ADV(N, P) .byte 2, L(N)-L(P) .balign 8 L(CIE): .set L(set0),L(ECIE)-L(SCIE) .long L(set0) /* CIE Length */ L(SCIE): .long 0 /* CIE Identifier Tag */ .byte 1 /* CIE Version */ .ascii "zR\0" /* CIE Augmentation */ .byte 1 /* CIE Code Alignment Factor */ .byte 0x78 /* CIE Data Alignment Factor */ .byte 0x10 /* CIE RA Column */ .byte 1 /* Augmentation size */ .byte 0x1b /* FDE Encoding (pcrel sdata4) */ .byte 0xc, 7, 8 /* DW_CFA_def_cfa, %rsp offset 8 */ .byte 0x80+16, 1 /* DW_CFA_offset, %rip offset 1*-8 */ .balign 8 L(ECIE): .set L(set1),L(EFDE1)-L(SFDE1) .long L(set1) /* FDE Length */ L(SFDE1): .long L(SFDE1)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW0)) /* Initial location */ .long L(UW4)-L(UW0) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW1, UW0) .byte 0xc, 6, 32 /* DW_CFA_def_cfa, %rbp 32 */ .byte 0x80+6, 2 /* DW_CFA_offset, %rbp 2*-8 */ ADV(UW2, UW1) .byte 0xa /* DW_CFA_remember_state */ .byte 0xc, 7, 8 /* DW_CFA_def_cfa, %rsp 8 */ .byte 0xc0+6 /* DW_CFA_restore, %rbp */ ADV(UW3, UW2) .byte 0xb /* DW_CFA_restore_state */ .balign 8 L(EFDE1): .set L(set2),L(EFDE2)-L(SFDE2) .long L(set2) /* FDE Length */ L(SFDE2): .long L(SFDE2)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW5)) /* Initial location */ .long L(UW7)-L(UW5) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW6, UW5) .byte 0xe /* DW_CFA_def_cfa_offset */ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ .balign 8 L(EFDE2): .set L(set3),L(EFDE3)-L(SFDE3) .long L(set3) /* FDE Length */ L(SFDE3): .long L(SFDE3)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW8)) /* Initial location */ .long L(UW11)-L(UW8) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW9, UW8) .byte 0xe /* DW_CFA_def_cfa_offset */ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ ADV(UW10, UW9) .byte 0xe, 8 /* DW_CFA_def_cfa_offset 8 */ L(EFDE3): .set L(set4),L(EFDE4)-L(SFDE4) .long L(set4) /* FDE Length */ L(SFDE4): .long L(SFDE4)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW12)) /* Initial location */ .long L(UW14)-L(UW12) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW13, UW12) .byte 0xe /* DW_CFA_def_cfa_offset */ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ .balign 8 L(EFDE4): .set L(set5),L(EFDE5)-L(SFDE5) .long L(set5) /* FDE Length */ L(SFDE5): .long L(SFDE5)-L(CIE) /* FDE CIE offset */ .long PCREL(L(UW15)) /* Initial location */ .long L(UW17)-L(UW15) /* Address range */ .byte 0 /* Augmentation size */ ADV(UW16, UW15) .byte 0xe /* DW_CFA_def_cfa_offset */ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ .balign 8 L(EFDE5): #ifdef __APPLE__ .subsections_via_symbols .section __LD,__compact_unwind,regular,debug /* compact unwind for ffi_call_unix64 */ .quad C(ffi_call_unix64) .set L1,L(UW4)-L(UW0) .long L1 .long 0x04000000 /* use dwarf unwind info */ .quad 0 .quad 0 /* compact unwind for ffi_closure_unix64_sse */ .quad C(ffi_closure_unix64_sse) .set L2,L(UW7)-L(UW5) .long L2 .long 0x04000000 /* use dwarf unwind info */ .quad 0 .quad 0 /* compact unwind for ffi_closure_unix64 */ .quad C(ffi_closure_unix64) .set L3,L(UW11)-L(UW8) .long L3 .long 0x04000000 /* use dwarf unwind info */ .quad 0 .quad 0 /* compact unwind for ffi_go_closure_unix64_sse */ .quad C(ffi_go_closure_unix64_sse) .set L4,L(UW14)-L(UW12) .long L4 .long 0x04000000 /* use dwarf unwind info */ .quad 0 .quad 0 /* compact unwind for ffi_go_closure_unix64 */ .quad C(ffi_go_closure_unix64) .set L5,L(UW17)-L(UW15) .long L5 .long 0x04000000 /* use dwarf unwind info */ .quad 0 .quad 0 #endif #endif /* __x86_64__ */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif ====================MIT==================== 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 AUTHORS OR COPYRIGHT HOLDERS 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. ====================MIT==================== 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 AUTHORS OR COPYRIGHT HOLDERS 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. ====================MIT==================== 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. ====================MIT==================== 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 AUTHORS OR COPYRIGHT HOLDERS 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. ====================MIT==================== 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 AUTHORS OR COPYRIGHT HOLDERS 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. */ ====================MIT==================== 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 AUTHORS OR COPYRIGHT HOLDERS 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. */