diff options
author | Mikhail Borisov <borisov.mikhail@gmail.com> | 2022-02-10 16:45:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:39 +0300 |
commit | a6a92afe03e02795227d2641b49819b687f088f8 (patch) | |
tree | f6984a1d27d5a7ec88a6fdd6e20cd5b7693b6ece /contrib/restricted/libffi/src/arm | |
parent | c6dc8b8bd530985bc4cce0137e9a5de32f1087cb (diff) | |
download | ydb-a6a92afe03e02795227d2641b49819b687f088f8.tar.gz |
Restoring authorship annotation for Mikhail Borisov <borisov.mikhail@gmail.com>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/libffi/src/arm')
-rw-r--r-- | contrib/restricted/libffi/src/arm/ffi.c | 1708 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/arm/ffitarget.h | 178 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/arm/internal.h | 14 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/arm/sysv.S | 770 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/arm/sysv_msvc_arm32.S | 622 |
5 files changed, 1646 insertions, 1646 deletions
diff --git a/contrib/restricted/libffi/src/arm/ffi.c b/contrib/restricted/libffi/src/arm/ffi.c index 4e270718a3..95cebf49ee 100644 --- a/contrib/restricted/libffi/src/arm/ffi.c +++ b/contrib/restricted/libffi/src/arm/ffi.c @@ -1,854 +1,854 @@ -/* ----------------------------------------------------------------------- - 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 <fficonfig.h> -#include <ffi.h> -#include <ffi_common.h> -#include <stdint.h> -#include <stdlib.h> -#include "internal.h" - -#if defined(_MSC_VER) && defined(_M_ARM) -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#endif - -#if FFI_EXEC_TRAMPOLINE_TABLE - -#ifdef __MACH__ -#include <mach/machine/vm_param.h> -#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 */ +/* ----------------------------------------------------------------------- + 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 <fficonfig.h> +#include <ffi.h> +#include <ffi_common.h> +#include <stdint.h> +#include <stdlib.h> +#include "internal.h" + +#if defined(_MSC_VER) && defined(_M_ARM) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#if FFI_EXEC_TRAMPOLINE_TABLE + +#ifdef __MACH__ +#include <mach/machine/vm_param.h> +#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 */ diff --git a/contrib/restricted/libffi/src/arm/ffitarget.h b/contrib/restricted/libffi/src/arm/ffitarget.h index cb57b84880..24e1de72b9 100644 --- a/contrib/restricted/libffi/src/arm/ffitarget.h +++ b/contrib/restricted/libffi/src/arm/ffitarget.h @@ -1,89 +1,89 @@ -/* -----------------------------------------------------------------*-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 +/* -----------------------------------------------------------------*-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 diff --git a/contrib/restricted/libffi/src/arm/internal.h b/contrib/restricted/libffi/src/arm/internal.h index 6cf0b2ae5d..418dc460f3 100644 --- a/contrib/restricted/libffi/src/arm/internal.h +++ b/contrib/restricted/libffi/src/arm/internal.h @@ -1,7 +1,7 @@ -#define ARM_TYPE_VFP_S 0 -#define ARM_TYPE_VFP_D 1 -#define ARM_TYPE_VFP_N 2 -#define ARM_TYPE_INT64 3 -#define ARM_TYPE_INT 4 -#define ARM_TYPE_VOID 5 -#define ARM_TYPE_STRUCT 6 +#define ARM_TYPE_VFP_S 0 +#define ARM_TYPE_VFP_D 1 +#define ARM_TYPE_VFP_N 2 +#define ARM_TYPE_INT64 3 +#define ARM_TYPE_INT 4 +#define ARM_TYPE_VOID 5 +#define ARM_TYPE_STRUCT 6 diff --git a/contrib/restricted/libffi/src/arm/sysv.S b/contrib/restricted/libffi/src/arm/sysv.S index 63180a4639..dec168db0b 100644 --- a/contrib/restricted/libffi/src/arm/sysv.S +++ b/contrib/restricted/libffi/src/arm/sysv.S @@ -1,385 +1,385 @@ -/* ----------------------------------------------------------------------- - 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 <fficonfig.h> -#include <ffi.h> -#include <ffi_cfi.h> -#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 <mach/machine/vm_param.h> - -.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 +/* ----------------------------------------------------------------------- + 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 <fficonfig.h> +#include <ffi.h> +#include <ffi_cfi.h> +#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 <mach/machine/vm_param.h> + +.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 diff --git a/contrib/restricted/libffi/src/arm/sysv_msvc_arm32.S b/contrib/restricted/libffi/src/arm/sysv_msvc_arm32.S index 5c99d0207a..29ab997467 100644 --- a/contrib/restricted/libffi/src/arm/sysv_msvc_arm32.S +++ b/contrib/restricted/libffi/src/arm/sysv_msvc_arm32.S @@ -1,311 +1,311 @@ -/* ----------------------------------------------------------------------- - sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc. - Copyright (c) 2011 Plausible Labs Cooperative, Inc. - Copyright (c) 2019 Microsoft Corporation. - - 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. - ----------------------------------------------------------------------- */ - -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> -#include <ffi_cfi.h> -#include "internal.h" -#include "ksarm.h" - - - ; 8 byte aligned AREA to support 8 byte aligned jump tables - MACRO - NESTED_ENTRY_FFI $FuncName, $AreaName, $ExceptHandler - - ; compute the function's labels - __DeriveFunctionLabels $FuncName - - ; determine the area we will put the function into -__FuncArea SETS "|.text|" - IF "$AreaName" != "" -__FuncArea SETS "$AreaName" - ENDIF - - ; set up the exception handler itself -__FuncExceptionHandler SETS "" - IF "$ExceptHandler" != "" -__FuncExceptionHandler SETS "|$ExceptHandler|" - ENDIF - - ; switch to the specified area, jump tables require 8 byte alignment - AREA $__FuncArea,CODE,CODEALIGN,ALIGN=3,READONLY - - ; export the function name - __ExportProc $FuncName - - ; flush any pending literal pool stuff - ROUT - - ; reset the state of the unwind code tracking - __ResetUnwindState - - MEND - -; MACRO -; TABLE_ENTRY $Type, $Table -;$Type_$Table -; MEND - -#define E(index,table) return_##index##_##table - - ; r0: stack - ; r1: frame - ; r2: fn - ; r3: vfp_used - - ; fake entry point exists only to generate exists only to - ; generate .pdata for exception unwinding - NESTED_ENTRY_FFI ffi_call_VFP_fake - PROLOG_PUSH {r11, lr} ; save fp and lr for unwind - - ALTERNATE_ENTRY ffi_call_VFP - cmp r3, #3 ; load only d0 if possible - vldrle d0, [r0] - vldmgt r0, {d0-d7} - add r0, r0, #64 ; discard the vfp register args - b ffi_call_SYSV - NESTED_END ffi_call_VFP_fake - - ; fake entry point exists only to generate exists only to - ; generate .pdata for exception unwinding - NESTED_ENTRY_FFI ffi_call_SYSV_fake - PROLOG_PUSH {r11, lr} ; save fp and lr for unwind - - ALTERNATE_ENTRY ffi_call_SYSV - stm r1, {fp, lr} - mov fp, r1 - - 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 - - ; Store values stored in registers. - ALIGN 8 - lsl r3, #3 - add r3, r3, pc - add r3, #8 - mov pc, r3 - - -E(ARM_TYPE_VFP_S, ffi_call) - ALIGN 8 - vstr s0, [r2] - pop {fp,pc} -E(ARM_TYPE_VFP_D, ffi_call) - ALIGN 8 - vstr d0, [r2] - pop {fp,pc} -E(ARM_TYPE_VFP_N, ffi_call) - ALIGN 8 - vstm r2, {d0-d3} - pop {fp,pc} -E(ARM_TYPE_INT64, ffi_call) - ALIGN 8 - str r1, [r2, #4] - nop -E(ARM_TYPE_INT, ffi_call) - ALIGN 8 - str r0, [r2] - pop {fp,pc} -E(ARM_TYPE_VOID, ffi_call) - ALIGN 8 - pop {fp,pc} - nop -E(ARM_TYPE_STRUCT, ffi_call) - ALIGN 8 - cmp r3, #ARM_TYPE_STRUCT - pop {fp,pc} - NESTED_END ffi_call_SYSV_fake - - IMPORT |ffi_closure_inner_SYSV| - /* - int ffi_closure_inner_SYSV - ( - cif, ; r0 - fun, ; r1 - user_data, ; r2 - frame ; r3 - ) - */ - - NESTED_ENTRY_FFI ffi_go_closure_SYSV - stmdb sp!, {r0-r3} ; save argument regs - ldr r0, [ip, #4] ; load cif - ldr r1, [ip, #8] ; load fun - mov r2, ip ; load user_data - b ffi_go_closure_SYSV_0 - NESTED_END ffi_go_closure_SYSV - - ; r3: ffi_closure - - ; fake entry point exists only to generate exists only to - ; generate .pdata for exception unwinding - NESTED_ENTRY_FFI ffi_closure_SYSV_fake - PROLOG_PUSH {r11, lr} ; save fp and lr for unwind - ALTERNATE_ENTRY ffi_closure_SYSV - ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment) - stmdb sp!, {r0-r3} ; save argument regs - - ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; ffi_closure->cif - ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; ffi_closure->fun - ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; ffi_closure->user_data - - ALTERNATE_ENTRY ffi_go_closure_SYSV_0 - add ip, sp, #16 ; compute entry sp - - sub sp, sp, #64+32 ; allocate frame parameter (sizeof(vfp_space) = 64, sizeof(result) = 32) - mov r3, sp ; set frame parameter - stmdb sp!, {ip,lr} - - bl ffi_closure_inner_SYSV ; call the Python closure - - ; Load values returned in registers. - add r2, sp, #64+8 ; address of closure_frame->result - bl ffi_closure_ret ; move result to correct register or memory for type - - ldmfd sp!, {ip,lr} - mov sp, ip ; restore stack pointer - mov pc, lr - NESTED_END ffi_closure_SYSV_fake - - IMPORT |ffi_closure_inner_VFP| - /* - int ffi_closure_inner_VFP - ( - cif, ; r0 - fun, ; r1 - user_data, ; r2 - frame ; r3 - ) - */ - - NESTED_ENTRY_FFI ffi_go_closure_VFP - stmdb sp!, {r0-r3} ; save argument regs - ldr r0, [ip, #4] ; load cif - ldr r1, [ip, #8] ; load fun - mov r2, ip ; load user_data - b ffi_go_closure_VFP_0 - NESTED_END ffi_go_closure_VFP - - ; fake entry point exists only to generate exists only to - ; generate .pdata for exception unwinding - ; r3: closure - NESTED_ENTRY_FFI ffi_closure_VFP_fake - PROLOG_PUSH {r11, lr} ; save fp and lr for unwind - - ALTERNATE_ENTRY ffi_closure_VFP - ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment) - stmdb sp!, {r0-r3} ; save argument regs - - 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 - - ALTERNATE_ENTRY ffi_go_closure_VFP_0 - add ip, sp, #16 ; compute entry sp - sub sp, sp, #32 ; save space for closure_frame->result - vstmdb sp!, {d0-d7} ; push closure_frame->vfp_space - - mov r3, sp ; save closure_frame - stmdb sp!, {ip,lr} - - bl ffi_closure_inner_VFP - - ; Load values returned in registers. - add r2, sp, #64+8 ; load result - bl ffi_closure_ret - ldmfd sp!, {ip,lr} - mov sp, ip ; restore stack pointer - mov pc, lr - NESTED_END ffi_closure_VFP_fake - -/* 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. */ - - NESTED_ENTRY_FFI ffi_closure_ret - stmdb sp!, {fp,lr} - - ALIGN 8 - lsl r0, #3 - add r0, r0, pc - add r0, #8 - mov pc, r0 - -E(ARM_TYPE_VFP_S, ffi_closure) - ALIGN 8 - vldr s0, [r2] - b call_epilogue -E(ARM_TYPE_VFP_D, ffi_closure) - ALIGN 8 - vldr d0, [r2] - b call_epilogue -E(ARM_TYPE_VFP_N, ffi_closure) - ALIGN 8 - vldm r2, {d0-d3} - b call_epilogue -E(ARM_TYPE_INT64, ffi_closure) - ALIGN 8 - ldr r1, [r2, #4] - nop -E(ARM_TYPE_INT, ffi_closure) - ALIGN 8 - ldr r0, [r2] - b call_epilogue -E(ARM_TYPE_VOID, ffi_closure) - ALIGN 8 - b call_epilogue - nop -E(ARM_TYPE_STRUCT, ffi_closure) - ALIGN 8 - b call_epilogue -call_epilogue - ldmfd sp!, {fp,pc} - NESTED_END ffi_closure_ret - - AREA |.trampoline|, DATA, THUMB, READONLY - EXPORT |ffi_arm_trampoline| -|ffi_arm_trampoline| DATA -thisproc adr ip, thisproc - stmdb sp!, {ip, r0} - ldr pc, [pc, #0] - DCD 0 - ;ENDP - - END
\ No newline at end of file +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc. + Copyright (c) 2011 Plausible Labs Cooperative, Inc. + Copyright (c) 2019 Microsoft Corporation. + + 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. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#include <ffi_cfi.h> +#include "internal.h" +#include "ksarm.h" + + + ; 8 byte aligned AREA to support 8 byte aligned jump tables + MACRO + NESTED_ENTRY_FFI $FuncName, $AreaName, $ExceptHandler + + ; compute the function's labels + __DeriveFunctionLabels $FuncName + + ; determine the area we will put the function into +__FuncArea SETS "|.text|" + IF "$AreaName" != "" +__FuncArea SETS "$AreaName" + ENDIF + + ; set up the exception handler itself +__FuncExceptionHandler SETS "" + IF "$ExceptHandler" != "" +__FuncExceptionHandler SETS "|$ExceptHandler|" + ENDIF + + ; switch to the specified area, jump tables require 8 byte alignment + AREA $__FuncArea,CODE,CODEALIGN,ALIGN=3,READONLY + + ; export the function name + __ExportProc $FuncName + + ; flush any pending literal pool stuff + ROUT + + ; reset the state of the unwind code tracking + __ResetUnwindState + + MEND + +; MACRO +; TABLE_ENTRY $Type, $Table +;$Type_$Table +; MEND + +#define E(index,table) return_##index##_##table + + ; r0: stack + ; r1: frame + ; r2: fn + ; r3: vfp_used + + ; fake entry point exists only to generate exists only to + ; generate .pdata for exception unwinding + NESTED_ENTRY_FFI ffi_call_VFP_fake + PROLOG_PUSH {r11, lr} ; save fp and lr for unwind + + ALTERNATE_ENTRY ffi_call_VFP + cmp r3, #3 ; load only d0 if possible + vldrle d0, [r0] + vldmgt r0, {d0-d7} + add r0, r0, #64 ; discard the vfp register args + b ffi_call_SYSV + NESTED_END ffi_call_VFP_fake + + ; fake entry point exists only to generate exists only to + ; generate .pdata for exception unwinding + NESTED_ENTRY_FFI ffi_call_SYSV_fake + PROLOG_PUSH {r11, lr} ; save fp and lr for unwind + + ALTERNATE_ENTRY ffi_call_SYSV + stm r1, {fp, lr} + mov fp, r1 + + 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 + + ; Store values stored in registers. + ALIGN 8 + lsl r3, #3 + add r3, r3, pc + add r3, #8 + mov pc, r3 + + +E(ARM_TYPE_VFP_S, ffi_call) + ALIGN 8 + vstr s0, [r2] + pop {fp,pc} +E(ARM_TYPE_VFP_D, ffi_call) + ALIGN 8 + vstr d0, [r2] + pop {fp,pc} +E(ARM_TYPE_VFP_N, ffi_call) + ALIGN 8 + vstm r2, {d0-d3} + pop {fp,pc} +E(ARM_TYPE_INT64, ffi_call) + ALIGN 8 + str r1, [r2, #4] + nop +E(ARM_TYPE_INT, ffi_call) + ALIGN 8 + str r0, [r2] + pop {fp,pc} +E(ARM_TYPE_VOID, ffi_call) + ALIGN 8 + pop {fp,pc} + nop +E(ARM_TYPE_STRUCT, ffi_call) + ALIGN 8 + cmp r3, #ARM_TYPE_STRUCT + pop {fp,pc} + NESTED_END ffi_call_SYSV_fake + + IMPORT |ffi_closure_inner_SYSV| + /* + int ffi_closure_inner_SYSV + ( + cif, ; r0 + fun, ; r1 + user_data, ; r2 + frame ; r3 + ) + */ + + NESTED_ENTRY_FFI ffi_go_closure_SYSV + stmdb sp!, {r0-r3} ; save argument regs + ldr r0, [ip, #4] ; load cif + ldr r1, [ip, #8] ; load fun + mov r2, ip ; load user_data + b ffi_go_closure_SYSV_0 + NESTED_END ffi_go_closure_SYSV + + ; r3: ffi_closure + + ; fake entry point exists only to generate exists only to + ; generate .pdata for exception unwinding + NESTED_ENTRY_FFI ffi_closure_SYSV_fake + PROLOG_PUSH {r11, lr} ; save fp and lr for unwind + ALTERNATE_ENTRY ffi_closure_SYSV + ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment) + stmdb sp!, {r0-r3} ; save argument regs + + ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; ffi_closure->cif + ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; ffi_closure->fun + ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; ffi_closure->user_data + + ALTERNATE_ENTRY ffi_go_closure_SYSV_0 + add ip, sp, #16 ; compute entry sp + + sub sp, sp, #64+32 ; allocate frame parameter (sizeof(vfp_space) = 64, sizeof(result) = 32) + mov r3, sp ; set frame parameter + stmdb sp!, {ip,lr} + + bl ffi_closure_inner_SYSV ; call the Python closure + + ; Load values returned in registers. + add r2, sp, #64+8 ; address of closure_frame->result + bl ffi_closure_ret ; move result to correct register or memory for type + + ldmfd sp!, {ip,lr} + mov sp, ip ; restore stack pointer + mov pc, lr + NESTED_END ffi_closure_SYSV_fake + + IMPORT |ffi_closure_inner_VFP| + /* + int ffi_closure_inner_VFP + ( + cif, ; r0 + fun, ; r1 + user_data, ; r2 + frame ; r3 + ) + */ + + NESTED_ENTRY_FFI ffi_go_closure_VFP + stmdb sp!, {r0-r3} ; save argument regs + ldr r0, [ip, #4] ; load cif + ldr r1, [ip, #8] ; load fun + mov r2, ip ; load user_data + b ffi_go_closure_VFP_0 + NESTED_END ffi_go_closure_VFP + + ; fake entry point exists only to generate exists only to + ; generate .pdata for exception unwinding + ; r3: closure + NESTED_ENTRY_FFI ffi_closure_VFP_fake + PROLOG_PUSH {r11, lr} ; save fp and lr for unwind + + ALTERNATE_ENTRY ffi_closure_VFP + ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment) + stmdb sp!, {r0-r3} ; save argument regs + + 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 + + ALTERNATE_ENTRY ffi_go_closure_VFP_0 + add ip, sp, #16 ; compute entry sp + sub sp, sp, #32 ; save space for closure_frame->result + vstmdb sp!, {d0-d7} ; push closure_frame->vfp_space + + mov r3, sp ; save closure_frame + stmdb sp!, {ip,lr} + + bl ffi_closure_inner_VFP + + ; Load values returned in registers. + add r2, sp, #64+8 ; load result + bl ffi_closure_ret + ldmfd sp!, {ip,lr} + mov sp, ip ; restore stack pointer + mov pc, lr + NESTED_END ffi_closure_VFP_fake + +/* 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. */ + + NESTED_ENTRY_FFI ffi_closure_ret + stmdb sp!, {fp,lr} + + ALIGN 8 + lsl r0, #3 + add r0, r0, pc + add r0, #8 + mov pc, r0 + +E(ARM_TYPE_VFP_S, ffi_closure) + ALIGN 8 + vldr s0, [r2] + b call_epilogue +E(ARM_TYPE_VFP_D, ffi_closure) + ALIGN 8 + vldr d0, [r2] + b call_epilogue +E(ARM_TYPE_VFP_N, ffi_closure) + ALIGN 8 + vldm r2, {d0-d3} + b call_epilogue +E(ARM_TYPE_INT64, ffi_closure) + ALIGN 8 + ldr r1, [r2, #4] + nop +E(ARM_TYPE_INT, ffi_closure) + ALIGN 8 + ldr r0, [r2] + b call_epilogue +E(ARM_TYPE_VOID, ffi_closure) + ALIGN 8 + b call_epilogue + nop +E(ARM_TYPE_STRUCT, ffi_closure) + ALIGN 8 + b call_epilogue +call_epilogue + ldmfd sp!, {fp,pc} + NESTED_END ffi_closure_ret + + AREA |.trampoline|, DATA, THUMB, READONLY + EXPORT |ffi_arm_trampoline| +|ffi_arm_trampoline| DATA +thisproc adr ip, thisproc + stmdb sp!, {ip, r0} + ldr pc, [pc, #0] + DCD 0 + ;ENDP + + END
\ No newline at end of file |