📄 ffi.c
字号:
/* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998 Cygnus Solutions Copyright (c) 2000 Hewlett Packard Company IA64 Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */#include <ffi.h>#include <ffi_common.h>#include <stdlib.h>#include "ia64_flags.h"/* Memory image of fp register contents. Should eventually be an fp *//* type long enough to hold an entire register. For now we use double. */typedef double float80;/* The stack layout at call to ffi_prep_args. Other_args will remain *//* on the stack for the actual call. Everything else we be transferred *//* to registers and popped by the assembly code. */struct ia64_args { long scratch[2]; /* Two scratch words at top of stack. */ /* Allows sp to be passed as arg pointer. */ void * r8_contents; /* Value to be passed in r8 */ long spare; /* Not used. */ float80 fp_regs[8]; /* Contents of 8 floating point argument */ /* registers. */ long out_regs[8]; /* Contents of the 8 out registers used */ /* for integer parameters. */ long other_args[0]; /* Arguments passed on stack, variable size */ /* Treated as continuation of out_regs. */};static size_t float_type_size(unsigned short tp){ switch(tp) { case FFI_TYPE_FLOAT: return sizeof(float); case FFI_TYPE_DOUBLE: return sizeof(double);#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: return sizeof(long double);#endif default: FFI_ASSERT(0); }}/* * Is type a struct containing at most n floats, doubles, or extended * doubles, all of the same fp type? * If so, set *element_type to the fp type. */static bool is_homogeneous_fp_aggregate(ffi_type * type, int n, unsigned short * element_type){ ffi_type **ptr; unsigned short element, struct_element; int type_set = 0; FFI_ASSERT(type != NULL); FFI_ASSERT(type->elements != NULL); ptr = &(type->elements[0]); while ((*ptr) != NULL) { switch((*ptr) -> type) { case FFI_TYPE_FLOAT: if (type_set && element != FFI_TYPE_FLOAT) return 0; if (--n < 0) return FALSE; type_set = 1; element = FFI_TYPE_FLOAT; break; case FFI_TYPE_DOUBLE: if (type_set && element != FFI_TYPE_DOUBLE) return 0; if (--n < 0) return FALSE; type_set = 1; element = FFI_TYPE_DOUBLE; break; case FFI_TYPE_STRUCT: if (!is_homogeneous_fp_aggregate(type, n, &struct_element)) return FALSE; if (type_set && struct_element != element) return FALSE; n -= (type -> size)/float_type_size(element); element = struct_element; if (n < 0) return FALSE; break; /* case FFI_TYPE_LONGDOUBLE: Not yet implemented. */ default: return FALSE; } ptr++; } *element_type = element; return TRUE; } /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments. It fills in the arguments in the structure referenced by stack. Returns nonzero if fp registers are used for arguments. */static boolffi_prep_args(struct ia64_args *stack, extended_cif *ecif, int bytes){ register long i, avn; register void **p_argv; register long *argp = stack -> out_regs; register float80 *fp_argp = stack -> fp_regs; register ffi_type **p_arg; /* For big return structs, r8 needs to contain the target address. */ /* Since r8 is otherwise dead, we set it unconditionally. */ stack -> r8_contents = ecif -> rvalue; i = 0; avn = ecif->cif->nargs; p_arg = ecif->cif->arg_types; p_argv = ecif->avalue; while (i < avn) { size_t z; /* z is in units of arg slots or words, not bytes. */ switch ((*p_arg)->type) { case FFI_TYPE_SINT8: z = 1; *(SINT64 *) argp = *(SINT8 *)(* p_argv); break; case FFI_TYPE_UINT8: z = 1; *(UINT64 *) argp = *(UINT8 *)(* p_argv); break; case FFI_TYPE_SINT16: z = 1; *(SINT64 *) argp = *(SINT16 *)(* p_argv); break; case FFI_TYPE_UINT16: z = 1; *(UINT64 *) argp = *(UINT16 *)(* p_argv); break; case FFI_TYPE_SINT32: z = 1; *(SINT64 *) argp = *(SINT32 *)(* p_argv); break; case FFI_TYPE_UINT32: z = 1; *(UINT64 *) argp = *(UINT32 *)(* p_argv); break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: z = 1; *(UINT64 *) argp = *(UINT64 *)(* p_argv); break; case FFI_TYPE_FLOAT: z = 1; if (fp_argp - stack->fp_regs < 8) { /* Note the conversion -- all the fp regs are loaded as doubles. */ *fp_argp++ = *(float *)(* p_argv); } /* Also put it into the integer registers or memory: */ *(UINT64 *) argp = *(UINT32 *)(* p_argv); break; case FFI_TYPE_DOUBLE: z = 1; if (fp_argp - stack->fp_regs < 8) *fp_argp++ = *(double *)(* p_argv); /* Also put it into the integer registers or memory: */ *(double *) argp = *(double *)(* p_argv); break; case FFI_TYPE_STRUCT: { size_t sz = (*p_arg)->size; unsigned short element_type; z = ((*p_arg)->size + SIZEOF_ARG - 1)/SIZEOF_ARG; if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) { int i; int nelements = sz/float_type_size(element_type); for (i = 0; i < nelements; ++i) { switch (element_type) { case FFI_TYPE_FLOAT: if (fp_argp - stack->fp_regs < 8) *fp_argp++ = ((float *)(* p_argv))[i]; break; case FFI_TYPE_DOUBLE: if (fp_argp - stack->fp_regs < 8) *fp_argp++ = ((double *)(* p_argv))[i]; break; default: /* Extended precision not yet implemented. */ abort(); } } } /* And pass it in integer registers as a struct, with */ /* its actual field sizes packed into registers. */ memcpy(argp, *p_argv, (*p_arg)->size); } break; default: FFI_ASSERT(0); } argp += z; i++, p_arg++, p_argv++; } return (fp_argp != stack -> fp_regs);}/* Perform machine dependent cif processing */ffi_statusffi_prep_cif_machdep(ffi_cif *cif){ long i, avn; bool is_simple = TRUE; long simple_flag = FFI_SIMPLE_V; /* Adjust cif->bytes to include space for the 2 scratch words, r8 register contents, spare word, the 8 fp register contents, and all 8 integer register contents. This will be removed before the call, though 2 scratch words must remain. */ cif->bytes += 4*sizeof(long) + 8 *sizeof(float80); if (cif->bytes < sizeof(struct ia64_args)) cif->bytes = sizeof(struct ia64_args); /* The stack must be double word aligned, so round bytes up appropriately. */ cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*)); avn = cif->nargs; if (avn <= 2) { for (i = 0; i < avn; ++i) { switch(cif -> arg_types[i] -> type) { case FFI_TYPE_SINT32: simple_flag = FFI_ADD_INT_ARG(simple_flag); break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: simple_flag = FFI_ADD_LONG_ARG(simple_flag); break; default: is_simple = FALSE; } } } else { is_simple = FALSE; } /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: cif->flags = FFI_TYPE_VOID; break; case FFI_TYPE_STRUCT: { size_t sz = cif -> rtype -> size; unsigned short element_type; is_simple = FALSE; if (is_homogeneous_fp_aggregate(cif -> rtype, 8, &element_type)) { int nelements = sz/float_type_size(element_type); if (nelements <= 1) { if (0 == nelements) { cif -> flags = FFI_TYPE_VOID; } else { cif -> flags = element_type; } } else { switch(element_type) { case FFI_TYPE_FLOAT: cif -> flags = FFI_IS_FLOAT_FP_AGGREGATE | nelements; break; case FFI_TYPE_DOUBLE: cif -> flags = FFI_IS_DOUBLE_FP_AGGREGATE | nelements; break; default: /* long double NYI */ abort(); } } break; } if (sz <= 32) { if (sz <= 8) { cif->flags = FFI_TYPE_INT; } else if (sz <= 16) { cif->flags = FFI_IS_SMALL_STRUCT2; } else if (sz <= 24) { cif->flags = FFI_IS_SMALL_STRUCT3; } else { cif->flags = FFI_IS_SMALL_STRUCT4; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -