Xtensa support
This commit is contained in:
@@ -143,6 +143,10 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
||||
#ifdef TILE
|
||||
&& (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
|
||||
#endif
|
||||
#ifdef XTENSA
|
||||
&& (cif->rtype->size > 16)
|
||||
#endif
|
||||
|
||||
)
|
||||
bytes = STACK_ARG_SIZE(sizeof(void*));
|
||||
#endif
|
||||
@@ -181,6 +185,10 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
||||
bytes = 10 * FFI_SIZEOF_ARG;
|
||||
}
|
||||
#endif
|
||||
#ifdef XTENSA
|
||||
if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4)
|
||||
bytes = 6*4;
|
||||
#endif
|
||||
|
||||
bytes += STACK_ARG_SIZE((*ptr)->size);
|
||||
}
|
||||
|
||||
298
src/xtensa/ffi.c
Normal file
298
src/xtensa/ffi.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 2013 Tensilica, Inc.
|
||||
|
||||
XTENSA Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
|
||||
/*
|
||||
|----------------------------------------|
|
||||
| |
|
||||
on entry to ffi_call ----> |----------------------------------------|
|
||||
| caller stack frame for registers a0-a3 |
|
||||
|----------------------------------------|
|
||||
| |
|
||||
| additional arguments |
|
||||
entry of the function ---> |----------------------------------------|
|
||||
| copy of function arguments a2-a7 |
|
||||
| - - - - - - - - - - - - - |
|
||||
| |
|
||||
|
||||
The area below the entry line becomes the new stack frame for the function.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define FFI_TYPE_STRUCT_REGS FFI_TYPE_LAST
|
||||
|
||||
|
||||
extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags,
|
||||
void(*fn)(void), unsigned nbytes, extended_cif*);
|
||||
extern void ffi_closure_SYSV(void) FFI_HIDDEN;
|
||||
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
switch(cif->rtype->type) {
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT16:
|
||||
cif->flags = cif->rtype->type;
|
||||
break;
|
||||
case FFI_TYPE_VOID:
|
||||
case FFI_TYPE_FLOAT:
|
||||
cif->flags = FFI_TYPE_UINT32;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
cif->flags = FFI_TYPE_UINT64; // cif->rtype->type;
|
||||
break;
|
||||
case FFI_TYPE_STRUCT:
|
||||
cif->flags = FFI_TYPE_STRUCT; //_REGS;
|
||||
/* Up to 16 bytes are returned in registers */
|
||||
if (cif->rtype->size > 4 * 4) {
|
||||
/* returned structure is referenced by a register; use 8 bytes
|
||||
(including 4 bytes for potential additional alignment) */
|
||||
cif->flags = FFI_TYPE_STRUCT;
|
||||
cif->bytes += 8;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cif->flags = FFI_TYPE_UINT32;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Round the stack up to a full 4 register frame, just in case
|
||||
(we use this size in movsp). This way, it's also a multiple of
|
||||
8 bytes for 64-bit arguments. */
|
||||
cif->bytes = ALIGN(cif->bytes, 16);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
void ffi_prep_args(extended_cif *ecif, unsigned char* stack)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long *addr;
|
||||
ffi_type **ptr;
|
||||
|
||||
union {
|
||||
void **v;
|
||||
char **c;
|
||||
signed char **sc;
|
||||
unsigned char **uc;
|
||||
signed short **ss;
|
||||
unsigned short **us;
|
||||
unsigned int **i;
|
||||
long long **ll;
|
||||
float **f;
|
||||
double **d;
|
||||
} p_argv;
|
||||
|
||||
/* Verify that everything is aligned up properly */
|
||||
FFI_ASSERT (((unsigned long) stack & 0x7) == 0);
|
||||
|
||||
p_argv.v = ecif->avalue;
|
||||
addr = (unsigned long*)stack;
|
||||
|
||||
/* structures with a size greater than 16 bytes are passed in memory */
|
||||
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 16)
|
||||
{
|
||||
*addr++ = (unsigned long)ecif->rvalue;
|
||||
}
|
||||
|
||||
for (i = ecif->cif->nargs, ptr = ecif->cif->arg_types;
|
||||
i > 0;
|
||||
i--, ptr++, p_argv.v++)
|
||||
{
|
||||
switch ((*ptr)->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
*addr++ = **p_argv.sc;
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
*addr++ = **p_argv.uc;
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
*addr++ = **p_argv.ss;
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
*addr++ = **p_argv.us;
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_POINTER:
|
||||
*addr++ = **p_argv.i;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
if (((unsigned long)addr & 4) != 0)
|
||||
addr++;
|
||||
*(unsigned long long*)addr = **p_argv.ll;
|
||||
addr += sizeof(unsigned long long) / sizeof (addr);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
{
|
||||
unsigned long offs;
|
||||
unsigned long size;
|
||||
|
||||
if (((unsigned long)addr & 4) != 0 && (*ptr)->alignment > 4)
|
||||
addr++;
|
||||
|
||||
offs = (unsigned long) addr - (unsigned long) stack;
|
||||
size = (*ptr)->size;
|
||||
|
||||
/* Entire structure must fit the argument registers or referenced */
|
||||
if (offs < FFI_REGISTER_NARGS * 4
|
||||
&& offs + size > FFI_REGISTER_NARGS * 4)
|
||||
addr = (unsigned long*) (stack + FFI_REGISTER_NARGS * 4);
|
||||
|
||||
memcpy((char*) addr, *p_argv.c, size);
|
||||
addr += (size + 3) / 4;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
extended_cif ecif;
|
||||
unsigned long rsize = cif->rtype->size;
|
||||
int flags = cif->flags;
|
||||
void *alloc = NULL;
|
||||
|
||||
ecif.cif = cif;
|
||||
ecif.avalue = avalue;
|
||||
|
||||
/* Note that for structures that are returned in registers (size <= 16 bytes)
|
||||
we allocate a temporary buffer and use memcpy to copy it to the final
|
||||
destination. The reason is that the target address might be misaligned or
|
||||
the length not a multiple of 4 bytes. Handling all those cases would be
|
||||
very complex. */
|
||||
|
||||
if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL))
|
||||
{
|
||||
alloc = alloca(ALIGN(rsize, 4));
|
||||
ecif.rvalue = alloc;
|
||||
}
|
||||
else
|
||||
{
|
||||
ecif.rvalue = rvalue;
|
||||
}
|
||||
|
||||
if (cif->abi != FFI_SYSV)
|
||||
FFI_ASSERT(0);
|
||||
|
||||
ffi_call_SYSV (ecif.rvalue, rsize, cif->flags, fn, cif->bytes, &ecif);
|
||||
|
||||
if (alloc != NULL && rvalue != NULL)
|
||||
memcpy(rvalue, alloc, rsize);
|
||||
}
|
||||
|
||||
extern void ffi_trampoline();
|
||||
extern void ffi_cacheflush(void* start, void* end);
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
/* copye trampoline to stack and patch 'ffi_closure_SYSV' pointer */
|
||||
memcpy(closure->tramp, ffi_trampoline, FFI_TRAMPOLINE_SIZE);
|
||||
*(unsigned int*)(&closure->tramp[8]) = (unsigned int)ffi_closure_SYSV;
|
||||
|
||||
// Do we have this function?
|
||||
// __builtin___clear_cache(closer->tramp, closer->tramp + FFI_TRAMPOLINE_SIZE)
|
||||
ffi_cacheflush(closure->tramp, closure->tramp + FFI_TRAMPOLINE_SIZE);
|
||||
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
closure->user_data = user_data;
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
|
||||
long FFI_HIDDEN
|
||||
ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
ffi_type **arg_types;
|
||||
void **avalue;
|
||||
int i, areg;
|
||||
|
||||
cif = closure->cif;
|
||||
if (cif->abi != FFI_SYSV)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
areg = 0;
|
||||
|
||||
int rtype = cif->rtype->type;
|
||||
if (rtype == FFI_TYPE_STRUCT && cif->rtype->size > 4 * 4)
|
||||
{
|
||||
rvalue = *values;
|
||||
areg++;
|
||||
}
|
||||
|
||||
cif = closure->cif;
|
||||
arg_types = cif->arg_types;
|
||||
avalue = alloca(cif->nargs * sizeof(void *));
|
||||
|
||||
for (i = 0; i < cif->nargs; i++)
|
||||
{
|
||||
if (arg_types[i]->alignment == 8 && (areg & 1) != 0)
|
||||
areg++;
|
||||
|
||||
// skip the entry 16,a1 framework, add 16 bytes (4 registers)
|
||||
if (areg == FFI_REGISTER_NARGS)
|
||||
areg += 4;
|
||||
|
||||
if (arg_types[i]->type == FFI_TYPE_STRUCT)
|
||||
{
|
||||
int numregs = ((arg_types[i]->size + 3) & ~3) / 4;
|
||||
if (areg < FFI_REGISTER_NARGS && areg + numregs > FFI_REGISTER_NARGS)
|
||||
areg = FFI_REGISTER_NARGS + 4;
|
||||
}
|
||||
|
||||
avalue[i] = &values[areg];
|
||||
areg += (arg_types[i]->size + 3) / 4;
|
||||
}
|
||||
|
||||
(closure->fun)(cif, rvalue, avalue, closure->user_data);
|
||||
|
||||
return rtype;
|
||||
}
|
||||
53
src/xtensa/ffitarget.h
Normal file
53
src/xtensa/ffitarget.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* -----------------------------------------------------------------*-C-*-
|
||||
ffitarget.h - Copyright (c) 2013 Tensilica, Inc.
|
||||
Target configuration macros for XTENSA.
|
||||
|
||||
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_LAST_ABI,
|
||||
FFI_DEFAULT_ABI = FFI_SYSV
|
||||
} ffi_abi;
|
||||
#endif
|
||||
|
||||
#define FFI_REGISTER_NARGS 6
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
#define FFI_TRAMPOLINE_SIZE 24
|
||||
|
||||
#endif
|
||||
253
src/xtensa/sysv.S
Normal file
253
src/xtensa/sysv.S
Normal file
@@ -0,0 +1,253 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
sysv.S - Copyright (c) 2013 Tensilica, Inc.
|
||||
|
||||
XTENSA 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>
|
||||
|
||||
#define ENTRY(name) .text; .globl name; .type name,@function; .align 4; name:
|
||||
#define END(name) .size name , . - name
|
||||
|
||||
/* Assert that the table below is in sync with ffi.h. */
|
||||
|
||||
#if FFI_TYPE_UINT8 != 5 \
|
||||
|| FFI_TYPE_SINT8 != 6 \
|
||||
|| FFI_TYPE_UINT16 != 7 \
|
||||
|| FFI_TYPE_SINT16 != 8 \
|
||||
|| FFI_TYPE_UINT32 != 9 \
|
||||
|| FFI_TYPE_SINT32 != 10 \
|
||||
|| FFI_TYPE_UINT64 != 11
|
||||
#error "xtensa/sysv.S out of sync with ffi.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* ffi_call_SYSV (rvalue, rbytes, flags, (*fnaddr)(), bytes, ecif)
|
||||
void *rvalue; a2
|
||||
unsigned long rbytes; a3
|
||||
unsigned flags; a4
|
||||
void (*fnaddr)(); a5
|
||||
unsigned long bytes; a6
|
||||
extended_cif* ecif) a7
|
||||
*/
|
||||
|
||||
ENTRY(ffi_call_SYSV)
|
||||
|
||||
entry a1, 32 # 32 byte frame for using call8 below
|
||||
|
||||
mov a10, a7 # a10(->arg0): ecif
|
||||
sub a11, a1, a6 # a11(->arg1): stack pointer
|
||||
mov a7, a1 # fp
|
||||
movsp a1, a11 # set new sp = old_sp - bytes
|
||||
|
||||
movi a8, ffi_prep_args
|
||||
callx8 a8 # ffi_prep_args(ecif, stack)
|
||||
|
||||
# prepare to move stack pointer back up to 6 arguments
|
||||
# note that 'bytes' is already aligned
|
||||
|
||||
movi a10, 6*4
|
||||
sub a11, a6, a10
|
||||
movgez a6, a10, a11
|
||||
add a6, a1, a6
|
||||
|
||||
|
||||
# we can pass up to 6 arguments in registers
|
||||
# for simplicity, just load 6 arguments
|
||||
# (the stack size is at least 32 bytes, so no risk to cross boundaries)
|
||||
|
||||
l32i a10, a1, 0
|
||||
l32i a11, a1, 4
|
||||
l32i a12, a1, 8
|
||||
l32i a13, a1, 12
|
||||
l32i a14, a1, 16
|
||||
l32i a15, a1, 20
|
||||
|
||||
# move stack pointer
|
||||
|
||||
movsp a1, a6
|
||||
|
||||
callx8 a5 # (*fn)(args...)
|
||||
|
||||
# Handle return value(s)
|
||||
|
||||
beqz a2, .Lexit
|
||||
|
||||
movi a5, FFI_TYPE_STRUCT
|
||||
bne a4, a5, .Lstore
|
||||
movi a5, 16
|
||||
blt a5, a3, .Lexit
|
||||
|
||||
s32i a10, a2, 0
|
||||
blti a3, 5, .Lexit
|
||||
addi a3, a3, -1
|
||||
s32i a11, a2, 4
|
||||
blti a3, 8, .Lexit
|
||||
s32i a12, a2, 8
|
||||
blti a3, 12, .Lexit
|
||||
s32i a13, a2, 12
|
||||
|
||||
.Lexit: retw
|
||||
|
||||
.Lstore:
|
||||
addi a4, a4, -FFI_TYPE_UINT8
|
||||
bgei a4, 7, .Lexit # should never happen
|
||||
movi a6, store_calls
|
||||
add a4, a4, a4
|
||||
addx4 a6, a4, a6 # store_table + idx * 8
|
||||
jx a6
|
||||
|
||||
.align 8
|
||||
store_calls:
|
||||
# UINT8
|
||||
s8i a10, a2, 0
|
||||
retw
|
||||
|
||||
# SINT8
|
||||
.align 8
|
||||
s8i a10, a2, 0
|
||||
retw
|
||||
|
||||
# UINT16
|
||||
.align 8
|
||||
s16i a10, a2, 0
|
||||
retw
|
||||
|
||||
# SINT16
|
||||
.align 8
|
||||
s16i a10, a2, 0
|
||||
retw
|
||||
|
||||
# UINT32
|
||||
.align 8
|
||||
s32i a10, a2, 0
|
||||
retw
|
||||
|
||||
# SINT32
|
||||
.align 8
|
||||
s32i a10, a2, 0
|
||||
retw
|
||||
|
||||
# UINT64
|
||||
.align 8
|
||||
s32i a10, a2, 0
|
||||
s32i a11, a2, 4
|
||||
retw
|
||||
|
||||
END(ffi_call_SYSV)
|
||||
|
||||
|
||||
/*
|
||||
* void ffi_cacheflush (unsigned long start, unsigned long end)
|
||||
*/
|
||||
|
||||
#define EXTRA_ARGS_SIZE 24
|
||||
|
||||
ENTRY(ffi_cacheflush)
|
||||
|
||||
entry a1, 16
|
||||
|
||||
1: dhwbi a2, 0
|
||||
ihi a2, 0
|
||||
addi a2, a2, 4
|
||||
blt a2, a3, 1b
|
||||
|
||||
retw
|
||||
|
||||
END(ffi_cacheflush)
|
||||
|
||||
/* ffi_trampoline is copied to the stack */
|
||||
|
||||
ENTRY(ffi_trampoline)
|
||||
|
||||
entry a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4) # [ 0]
|
||||
j 2f # [ 3]
|
||||
.align 4 # [ 6]
|
||||
1: .long 0 # [ 8]
|
||||
2: l32r a15, 1b # [12]
|
||||
_mov a14, a0 # [15]
|
||||
callx0 a15 # [18]
|
||||
# [21]
|
||||
END(ffi_trampoline)
|
||||
|
||||
/*
|
||||
* ffi_closure()
|
||||
*
|
||||
* a0: closure + 21
|
||||
* a14: return address (a0)
|
||||
*/
|
||||
|
||||
ENTRY(ffi_closure_SYSV)
|
||||
|
||||
/* intentionally omitting entry here */
|
||||
|
||||
# restore return address (a0) and move pointer to closure to a10
|
||||
addi a10, a0, -21
|
||||
mov a0, a14
|
||||
|
||||
# allow up to 4 arguments as return values
|
||||
addi a11, a1, 4 * 4
|
||||
|
||||
# save up to 6 arguments to stack (allocated by entry below)
|
||||
s32i a2, a11, 0
|
||||
s32i a3, a11, 4
|
||||
s32i a4, a11, 8
|
||||
s32i a5, a11, 12
|
||||
s32i a6, a11, 16
|
||||
s32i a7, a11, 20
|
||||
|
||||
movi a8, ffi_closure_SYSV_inner
|
||||
mov a12, a1
|
||||
callx8 a8 # .._inner(*closure, **avalue, *rvalue)
|
||||
|
||||
# load up to four return arguments
|
||||
l32i a2, a1, 0
|
||||
l32i a3, a1, 4
|
||||
l32i a4, a1, 8
|
||||
l32i a5, a1, 12
|
||||
|
||||
# (sign-)extend return value
|
||||
movi a11, FFI_TYPE_UINT8
|
||||
bne a10, a11, 1f
|
||||
extui a2, a2, 0, 8
|
||||
retw
|
||||
|
||||
1: movi a11, FFI_TYPE_SINT8
|
||||
bne a10, a11, 1f
|
||||
sext a2, a2, 7
|
||||
retw
|
||||
|
||||
1: movi a11, FFI_TYPE_UINT16
|
||||
bne a10, a11, 1f
|
||||
extui a2, a2, 0, 16
|
||||
retw
|
||||
|
||||
1: movi a11, FFI_TYPE_SINT16
|
||||
bne a10, a11, 1f
|
||||
sext a2, a2, 15
|
||||
|
||||
1: retw
|
||||
|
||||
END(ffi_closure_SYSV)
|
||||
Reference in New Issue
Block a user