1f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* ----------------------------------------------------------------------- 2f180099ec619325d28c6a76a38df5419ef69651eThomas Heller prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. 3f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 4f180099ec619325d28c6a76a38df5419ef69651eThomas Heller Permission is hereby granted, free of charge, to any person obtaining 5f180099ec619325d28c6a76a38df5419ef69651eThomas Heller a copy of this software and associated documentation files (the 6f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ``Software''), to deal in the Software without restriction, including 7f180099ec619325d28c6a76a38df5419ef69651eThomas Heller without limitation the rights to use, copy, modify, merge, publish, 8f180099ec619325d28c6a76a38df5419ef69651eThomas Heller distribute, sublicense, and/or sell copies of the Software, and to 9f180099ec619325d28c6a76a38df5419ef69651eThomas Heller permit persons to whom the Software is furnished to do so, subject to 10f180099ec619325d28c6a76a38df5419ef69651eThomas Heller the following conditions: 11f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 12f180099ec619325d28c6a76a38df5419ef69651eThomas Heller The above copyright notice and this permission notice shall be included 13f180099ec619325d28c6a76a38df5419ef69651eThomas Heller in all copies or substantial portions of the Software. 14f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 15f180099ec619325d28c6a76a38df5419ef69651eThomas Heller THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS 16f180099ec619325d28c6a76a38df5419ef69651eThomas Heller OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17f180099ec619325d28c6a76a38df5419ef69651eThomas Heller MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18f180099ec619325d28c6a76a38df5419ef69651eThomas Heller IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR 19f180099ec619325d28c6a76a38df5419ef69651eThomas Heller OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21f180099ec619325d28c6a76a38df5419ef69651eThomas Heller OTHER DEALINGS IN THE SOFTWARE. 22f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ----------------------------------------------------------------------- */ 23f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 24f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#include <ffi.h> 25f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#include <ffi_common.h> 26f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#include <stdlib.h> 27f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 28f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 29f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* Round up to FFI_SIZEOF_ARG. */ 30f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 31f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) 32f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 33f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* Perform machine independent initialization of aggregate type 34f180099ec619325d28c6a76a38df5419ef69651eThomas Heller specifications. */ 35f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 36f180099ec619325d28c6a76a38df5419ef69651eThomas Hellerstatic ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) 37f180099ec619325d28c6a76a38df5419ef69651eThomas Heller{ 38f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ffi_type **ptr; 39f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 40f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT(arg != NULL); 41f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 42f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /*@-usedef@*/ 43f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 44f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT(arg->elements != NULL); 45f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT(arg->size == 0); 46f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT(arg->alignment == 0); 47f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 48f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ptr = &(arg->elements[0]); 49f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 50f180099ec619325d28c6a76a38df5419ef69651eThomas Heller while ((*ptr) != NULL) 51f180099ec619325d28c6a76a38df5419ef69651eThomas Heller { 52f180099ec619325d28c6a76a38df5419ef69651eThomas Heller if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) 53f180099ec619325d28c6a76a38df5419ef69651eThomas Heller return FFI_BAD_TYPEDEF; 54f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 55f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Perform a sanity check on the argument type */ 56f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT_VALID_TYPE(*ptr); 57f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 58f180099ec619325d28c6a76a38df5419ef69651eThomas Heller arg->size = ALIGN(arg->size, (*ptr)->alignment); 59f180099ec619325d28c6a76a38df5419ef69651eThomas Heller arg->size += (*ptr)->size; 60f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 61f180099ec619325d28c6a76a38df5419ef69651eThomas Heller arg->alignment = (arg->alignment > (*ptr)->alignment) ? 62f180099ec619325d28c6a76a38df5419ef69651eThomas Heller arg->alignment : (*ptr)->alignment; 63f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 64f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ptr++; 65f180099ec619325d28c6a76a38df5419ef69651eThomas Heller } 66f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 67f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Structure size includes tail padding. This is important for 68f180099ec619325d28c6a76a38df5419ef69651eThomas Heller structures that fit in one register on ABIs like the PowerPC64 69f180099ec619325d28c6a76a38df5419ef69651eThomas Heller Linux ABI that right justify small structs in a register. 70f180099ec619325d28c6a76a38df5419ef69651eThomas Heller It's also needed for nested structure layout, for example 71f180099ec619325d28c6a76a38df5419ef69651eThomas Heller struct A { long a; char b; }; struct B { struct A x; char y; }; 72f180099ec619325d28c6a76a38df5419ef69651eThomas Heller should find y at an offset of 2*sizeof(long) and result in a 73f180099ec619325d28c6a76a38df5419ef69651eThomas Heller total size of 3*sizeof(long). */ 74f180099ec619325d28c6a76a38df5419ef69651eThomas Heller arg->size = ALIGN (arg->size, arg->alignment); 75f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 76f180099ec619325d28c6a76a38df5419ef69651eThomas Heller if (arg->size == 0) 77f180099ec619325d28c6a76a38df5419ef69651eThomas Heller return FFI_BAD_TYPEDEF; 78f180099ec619325d28c6a76a38df5419ef69651eThomas Heller else 79f180099ec619325d28c6a76a38df5419ef69651eThomas Heller return FFI_OK; 80f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 81f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /*@=usedef@*/ 82f180099ec619325d28c6a76a38df5419ef69651eThomas Heller} 83f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 84f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* Perform machine independent ffi_cif preparation, then call 85f180099ec619325d28c6a76a38df5419ef69651eThomas Heller machine dependent routine. */ 86f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 87f180099ec619325d28c6a76a38df5419ef69651eThomas Hellerffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, 88f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ffi_abi abi, unsigned int nargs, 89f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, 90f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /*@dependent@*/ ffi_type **atypes) 91f180099ec619325d28c6a76a38df5419ef69651eThomas Heller{ 92f180099ec619325d28c6a76a38df5419ef69651eThomas Heller unsigned bytes = 0; 93f180099ec619325d28c6a76a38df5419ef69651eThomas Heller unsigned int i; 94f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ffi_type **ptr; 95f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 96f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT(cif != NULL); 97f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); 98f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 99f180099ec619325d28c6a76a38df5419ef69651eThomas Heller cif->abi = abi; 100f180099ec619325d28c6a76a38df5419ef69651eThomas Heller cif->arg_types = atypes; 101f180099ec619325d28c6a76a38df5419ef69651eThomas Heller cif->nargs = nargs; 102f180099ec619325d28c6a76a38df5419ef69651eThomas Heller cif->rtype = rtype; 103f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 104f180099ec619325d28c6a76a38df5419ef69651eThomas Heller cif->flags = 0; 105f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 106f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Initialize the return type if necessary */ 107f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /*@-usedef@*/ 108f180099ec619325d28c6a76a38df5419ef69651eThomas Heller if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) 109f180099ec619325d28c6a76a38df5419ef69651eThomas Heller return FFI_BAD_TYPEDEF; 110f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /*@=usedef@*/ 111f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 112f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Perform a sanity check on the return type */ 113f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT_VALID_TYPE(cif->rtype); 114f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 115f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ 116f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#if !defined M68K && !defined __x86_64__ && !defined S390 117f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Make space for the return structure pointer */ 118f180099ec619325d28c6a76a38df5419ef69651eThomas Heller if (cif->rtype->type == FFI_TYPE_STRUCT 11931221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#ifdef _WIN32 12031221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower && (cif->rtype->size > 8) /* MSVC returns small structs in registers */ 12131221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#endif 122f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#ifdef SPARC 123f180099ec619325d28c6a76a38df5419ef69651eThomas Heller && (cif->abi != FFI_V9 || cif->rtype->size > 32) 124f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif 125f180099ec619325d28c6a76a38df5419ef69651eThomas Heller ) 126f180099ec619325d28c6a76a38df5419ef69651eThomas Heller bytes = STACK_ARG_SIZE(sizeof(void*)); 127f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif 128f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 129f180099ec619325d28c6a76a38df5419ef69651eThomas Heller for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) 130f180099ec619325d28c6a76a38df5419ef69651eThomas Heller { 131f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 132f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Initialize any uninitialized aggregate type definitions */ 133f180099ec619325d28c6a76a38df5419ef69651eThomas Heller if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) 134f180099ec619325d28c6a76a38df5419ef69651eThomas Heller return FFI_BAD_TYPEDEF; 135f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 136f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Perform a sanity check on the argument type, do this 137f180099ec619325d28c6a76a38df5419ef69651eThomas Heller check after the initialization. */ 138f180099ec619325d28c6a76a38df5419ef69651eThomas Heller FFI_ASSERT_VALID_TYPE(*ptr); 139f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 140f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#if !defined __x86_64__ && !defined S390 141f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#ifdef SPARC 142f180099ec619325d28c6a76a38df5419ef69651eThomas Heller if (((*ptr)->type == FFI_TYPE_STRUCT 143f180099ec619325d28c6a76a38df5419ef69651eThomas Heller && ((*ptr)->size > 16 || cif->abi != FFI_V9)) 144f180099ec619325d28c6a76a38df5419ef69651eThomas Heller || ((*ptr)->type == FFI_TYPE_LONGDOUBLE 145f180099ec619325d28c6a76a38df5419ef69651eThomas Heller && cif->abi != FFI_V9)) 14631221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower bytes += sizeof(void*); 14731221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower else 14831221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#elif defined (_WIN64) 14931221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8)) 15031221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower bytes += sizeof(void*); 151f180099ec619325d28c6a76a38df5419ef69651eThomas Heller else 152f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif 153f180099ec619325d28c6a76a38df5419ef69651eThomas Heller { 154f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#if !defined(_MSC_VER) && !defined(__MINGW32__) 155f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Don't know if this is a libffi bug or not. At least on 156f180099ec619325d28c6a76a38df5419ef69651eThomas Heller Windows with MSVC, function call parameters are *not* 157f180099ec619325d28c6a76a38df5419ef69651eThomas Heller aligned in the same way as structure fields are, they are 158f180099ec619325d28c6a76a38df5419ef69651eThomas Heller only aligned in integer boundaries. 159f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 160f180099ec619325d28c6a76a38df5419ef69651eThomas Heller This doesn't do any harm for cdecl functions and closures, 161f180099ec619325d28c6a76a38df5419ef69651eThomas Heller since the caller cleans up the stack, but it is wrong for 162f180099ec619325d28c6a76a38df5419ef69651eThomas Heller stdcall functions where the callee cleans. 163f180099ec619325d28c6a76a38df5419ef69651eThomas Heller */ 164f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 165f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Add any padding if necessary */ 166f180099ec619325d28c6a76a38df5419ef69651eThomas Heller if (((*ptr)->alignment - 1) & bytes) 167f180099ec619325d28c6a76a38df5419ef69651eThomas Heller bytes = ALIGN(bytes, (*ptr)->alignment); 168f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 169f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif 170f180099ec619325d28c6a76a38df5419ef69651eThomas Heller bytes += STACK_ARG_SIZE((*ptr)->size); 171f180099ec619325d28c6a76a38df5419ef69651eThomas Heller } 172f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif 173f180099ec619325d28c6a76a38df5419ef69651eThomas Heller } 174f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 17531221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#ifdef _WIN64 17631221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ 17731221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower if (bytes < 40) 17831221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower bytes = 40; 17931221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#endif 18031221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower 181f180099ec619325d28c6a76a38df5419ef69651eThomas Heller cif->bytes = bytes; 182f180099ec619325d28c6a76a38df5419ef69651eThomas Heller 183f180099ec619325d28c6a76a38df5419ef69651eThomas Heller /* Perform machine dependent cif processing */ 184f180099ec619325d28c6a76a38df5419ef69651eThomas Heller return ffi_prep_cif_machdep(cif); 185f180099ec619325d28c6a76a38df5419ef69651eThomas Heller} 186