mirror of
https://github.com/partic2/libffi
synced 2026-11-09 17:47:19 +00:00
This implements go closures for RISC-V. It has been tested on riscv64-suse-linux and against the libgo testsuite.
294 lines
7.9 KiB
ArmAsm
294 lines
7.9 KiB
ArmAsm
/* -----------------------------------------------------------------------
|
|
ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
|
|
2015 Andrew Waterman <waterman@cs.berkeley.edu>
|
|
2018 Stef O'Rear <sorear2@gmail.com>
|
|
|
|
RISC-V 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 aliases so that we can handle all ABIs uniformly */
|
|
|
|
#if __SIZEOF_POINTER__ == 8
|
|
#define PTRS 8
|
|
#define LARG ld
|
|
#define SARG sd
|
|
#else
|
|
#define PTRS 4
|
|
#define LARG lw
|
|
#define SARG sw
|
|
#endif
|
|
|
|
#if __riscv_float_abi_double
|
|
#define FLTS 8
|
|
#define FLARG fld
|
|
#define FSARG fsd
|
|
#elif __riscv_float_abi_single
|
|
#define FLTS 4
|
|
#define FLARG flw
|
|
#define FSARG fsw
|
|
#else
|
|
#define FLTS 0
|
|
#endif
|
|
|
|
#define fp s0
|
|
|
|
.text
|
|
.globl ffi_call_asm
|
|
.type ffi_call_asm, @function
|
|
.hidden ffi_call_asm
|
|
/*
|
|
struct call_context {
|
|
floatreg fa[8];
|
|
intreg a[8];
|
|
intreg pad[rv32 ? 2 : 0];
|
|
intreg save_fp, save_ra;
|
|
}
|
|
void ffi_call_asm (size_t *stackargs, struct call_context *regargs,
|
|
void (*fn) (void), void *closure);
|
|
*/
|
|
|
|
#define FRAME_LEN (8 * FLTS + 8 * PTRS + 16)
|
|
|
|
ffi_call_asm:
|
|
.cfi_startproc
|
|
|
|
/*
|
|
We are NOT going to set up an ordinary stack frame. In order to pass
|
|
the stacked args to the called function, we adjust our stack pointer to
|
|
a0, which is in the _caller's_ alloca area. We establish our own stack
|
|
frame at the end of the call_context.
|
|
|
|
Anything below the arguments will be freed at this point, although we
|
|
preserve the call_context so that it can be read back in the caller.
|
|
*/
|
|
|
|
.cfi_def_cfa 11, FRAME_LEN # interim CFA based on a1
|
|
SARG fp, FRAME_LEN - 2*PTRS(a1)
|
|
.cfi_offset 8, -2*PTRS
|
|
SARG ra, FRAME_LEN - 1*PTRS(a1)
|
|
.cfi_offset 1, -1*PTRS
|
|
|
|
addi fp, a1, FRAME_LEN
|
|
mv sp, a0
|
|
.cfi_def_cfa 8, 0 # our frame is fully set up
|
|
|
|
# Load arguments
|
|
mv t1, a2
|
|
mv t2, a3
|
|
|
|
#if FLTS
|
|
FLARG fa0, -FRAME_LEN+0*FLTS(fp)
|
|
FLARG fa1, -FRAME_LEN+1*FLTS(fp)
|
|
FLARG fa2, -FRAME_LEN+2*FLTS(fp)
|
|
FLARG fa3, -FRAME_LEN+3*FLTS(fp)
|
|
FLARG fa4, -FRAME_LEN+4*FLTS(fp)
|
|
FLARG fa5, -FRAME_LEN+5*FLTS(fp)
|
|
FLARG fa6, -FRAME_LEN+6*FLTS(fp)
|
|
FLARG fa7, -FRAME_LEN+7*FLTS(fp)
|
|
#endif
|
|
|
|
LARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp)
|
|
LARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp)
|
|
LARG a2, -FRAME_LEN+8*FLTS+2*PTRS(fp)
|
|
LARG a3, -FRAME_LEN+8*FLTS+3*PTRS(fp)
|
|
LARG a4, -FRAME_LEN+8*FLTS+4*PTRS(fp)
|
|
LARG a5, -FRAME_LEN+8*FLTS+5*PTRS(fp)
|
|
LARG a6, -FRAME_LEN+8*FLTS+6*PTRS(fp)
|
|
LARG a7, -FRAME_LEN+8*FLTS+7*PTRS(fp)
|
|
|
|
/* Call */
|
|
jalr t1
|
|
|
|
/* Save return values - only a0/a1 (fa0/fa1) are used */
|
|
#if FLTS
|
|
FSARG fa0, -FRAME_LEN+0*FLTS(fp)
|
|
FSARG fa1, -FRAME_LEN+1*FLTS(fp)
|
|
#endif
|
|
|
|
SARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp)
|
|
SARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp)
|
|
|
|
/* Restore and return */
|
|
addi sp, fp, -FRAME_LEN
|
|
.cfi_def_cfa 2, FRAME_LEN
|
|
LARG ra, -1*PTRS(fp)
|
|
.cfi_restore 1
|
|
LARG fp, -2*PTRS(fp)
|
|
.cfi_restore 8
|
|
ret
|
|
.cfi_endproc
|
|
.size ffi_call_asm, .-ffi_call_asm
|
|
|
|
|
|
/*
|
|
ffi_closure_asm. Expects address of the passed-in ffi_closure in t1.
|
|
void ffi_closure_inner (ffi_cif *cif,
|
|
void (*fun) (ffi_cif *, void *, void **, void *),
|
|
void *user_data,
|
|
size_t *stackargs, struct call_context *regargs)
|
|
*/
|
|
|
|
.globl ffi_closure_asm
|
|
.hidden ffi_closure_asm
|
|
.type ffi_closure_asm, @function
|
|
ffi_closure_asm:
|
|
.cfi_startproc
|
|
|
|
addi sp, sp, -FRAME_LEN
|
|
.cfi_def_cfa_offset FRAME_LEN
|
|
|
|
/* make a frame */
|
|
SARG fp, FRAME_LEN - 2*PTRS(sp)
|
|
.cfi_offset 8, -2*PTRS
|
|
SARG ra, FRAME_LEN - 1*PTRS(sp)
|
|
.cfi_offset 1, -1*PTRS
|
|
addi fp, sp, FRAME_LEN
|
|
|
|
/* save arguments */
|
|
#if FLTS
|
|
FSARG fa0, 0*FLTS(sp)
|
|
FSARG fa1, 1*FLTS(sp)
|
|
FSARG fa2, 2*FLTS(sp)
|
|
FSARG fa3, 3*FLTS(sp)
|
|
FSARG fa4, 4*FLTS(sp)
|
|
FSARG fa5, 5*FLTS(sp)
|
|
FSARG fa6, 6*FLTS(sp)
|
|
FSARG fa7, 7*FLTS(sp)
|
|
#endif
|
|
|
|
SARG a0, 8*FLTS+0*PTRS(sp)
|
|
SARG a1, 8*FLTS+1*PTRS(sp)
|
|
SARG a2, 8*FLTS+2*PTRS(sp)
|
|
SARG a3, 8*FLTS+3*PTRS(sp)
|
|
SARG a4, 8*FLTS+4*PTRS(sp)
|
|
SARG a5, 8*FLTS+5*PTRS(sp)
|
|
SARG a6, 8*FLTS+6*PTRS(sp)
|
|
SARG a7, 8*FLTS+7*PTRS(sp)
|
|
|
|
/* enter C */
|
|
LARG a0, FFI_TRAMPOLINE_SIZE+0*PTRS(t1)
|
|
LARG a1, FFI_TRAMPOLINE_SIZE+1*PTRS(t1)
|
|
LARG a2, FFI_TRAMPOLINE_SIZE+2*PTRS(t1)
|
|
addi a3, sp, FRAME_LEN
|
|
mv a4, sp
|
|
|
|
call ffi_closure_inner
|
|
|
|
/* return values */
|
|
#if FLTS
|
|
FLARG fa0, 0*FLTS(sp)
|
|
FLARG fa1, 1*FLTS(sp)
|
|
#endif
|
|
|
|
LARG a0, 8*FLTS+0*PTRS(sp)
|
|
LARG a1, 8*FLTS+1*PTRS(sp)
|
|
|
|
/* restore and return */
|
|
LARG ra, FRAME_LEN-1*PTRS(sp)
|
|
.cfi_restore 1
|
|
LARG fp, FRAME_LEN-2*PTRS(sp)
|
|
.cfi_restore 8
|
|
addi sp, sp, FRAME_LEN
|
|
.cfi_def_cfa_offset 0
|
|
ret
|
|
.cfi_endproc
|
|
.size ffi_closure_asm, .-ffi_closure_asm
|
|
|
|
/*
|
|
ffi_go_closure_asm. Expects address of the passed-in ffi_go_closure in t2.
|
|
void ffi_closure_inner (ffi_cif *cif,
|
|
void (*fun) (ffi_cif *, void *, void **, void *),
|
|
void *user_data,
|
|
size_t *stackargs, struct call_context *regargs)
|
|
*/
|
|
|
|
.globl ffi_go_closure_asm
|
|
.hidden ffi_go_closure_asm
|
|
.type ffi_go_closure_asm, @function
|
|
ffi_go_closure_asm:
|
|
.cfi_startproc
|
|
|
|
addi sp, sp, -FRAME_LEN
|
|
.cfi_def_cfa_offset FRAME_LEN
|
|
|
|
/* make a frame */
|
|
SARG fp, FRAME_LEN - 2*PTRS(sp)
|
|
.cfi_offset 8, -2*PTRS
|
|
SARG ra, FRAME_LEN - 1*PTRS(sp)
|
|
.cfi_offset 1, -1*PTRS
|
|
addi fp, sp, FRAME_LEN
|
|
|
|
/* save arguments */
|
|
#if FLTS
|
|
FSARG fa0, 0*FLTS(sp)
|
|
FSARG fa1, 1*FLTS(sp)
|
|
FSARG fa2, 2*FLTS(sp)
|
|
FSARG fa3, 3*FLTS(sp)
|
|
FSARG fa4, 4*FLTS(sp)
|
|
FSARG fa5, 5*FLTS(sp)
|
|
FSARG fa6, 6*FLTS(sp)
|
|
FSARG fa7, 7*FLTS(sp)
|
|
#endif
|
|
|
|
SARG a0, 8*FLTS+0*PTRS(sp)
|
|
SARG a1, 8*FLTS+1*PTRS(sp)
|
|
SARG a2, 8*FLTS+2*PTRS(sp)
|
|
SARG a3, 8*FLTS+3*PTRS(sp)
|
|
SARG a4, 8*FLTS+4*PTRS(sp)
|
|
SARG a5, 8*FLTS+5*PTRS(sp)
|
|
SARG a6, 8*FLTS+6*PTRS(sp)
|
|
SARG a7, 8*FLTS+7*PTRS(sp)
|
|
|
|
/* enter C */
|
|
LARG a0, 1*PTRS(t2)
|
|
LARG a1, 2*PTRS(t2)
|
|
mv a2, t2
|
|
addi a3, sp, FRAME_LEN
|
|
mv a4, sp
|
|
|
|
call ffi_closure_inner
|
|
|
|
/* return values */
|
|
#if FLTS
|
|
FLARG fa0, 0*FLTS(sp)
|
|
FLARG fa1, 1*FLTS(sp)
|
|
#endif
|
|
|
|
LARG a0, 8*FLTS+0*PTRS(sp)
|
|
LARG a1, 8*FLTS+1*PTRS(sp)
|
|
|
|
/* restore and return */
|
|
LARG ra, FRAME_LEN-1*PTRS(sp)
|
|
.cfi_restore 1
|
|
LARG fp, FRAME_LEN-2*PTRS(sp)
|
|
.cfi_restore 8
|
|
addi sp, sp, FRAME_LEN
|
|
.cfi_def_cfa_offset 0
|
|
ret
|
|
.cfi_endproc
|
|
.size ffi_go_closure_asm, .-ffi_go_closure_asm
|