aboutsummaryrefslogtreecommitdiff
path: root/libffi/src/loongarch64/sysv.S
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src/loongarch64/sysv.S')
-rw-r--r--libffi/src/loongarch64/sysv.S327
1 files changed, 327 insertions, 0 deletions
diff --git a/libffi/src/loongarch64/sysv.S b/libffi/src/loongarch64/sysv.S
new file mode 100644
index 0000000..aa7bde2
--- /dev/null
+++ b/libffi/src/loongarch64/sysv.S
@@ -0,0 +1,327 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2022 Xu Chenghua <xuchenghua@loongson.cn>
+ 2022 Cheng Lulu <chenglulu@loongson.cn>
+
+ LoongArch 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.d
+# define SARG st.d
+#else
+# define PTRS 4
+# define LARG ld.w
+# define SARG st.w
+#endif
+
+#if defined(__loongarch_single_float)
+# define FLTS 4
+# define FLD fld.w
+# define FST fst.w
+#elif defined(__loongarch_double_float)
+# define FLTS 8
+# define FLARG fld.d
+# define FSARG fst.d
+#elif defined(__loongarch_soft_float)
+# define FLTS 0
+#else
+#error unsupported LoongArch floating-point ABI
+#endif
+
+ .text
+ .globl ffi_call_asm
+ .type ffi_call_asm, @function
+ .hidden ffi_call_asm
+/* struct call_context
+ {
+ ABI_FLOAT fa[8];
+ size_t a[10];
+ }
+
+ - 8 floating point parameter/result registers (fa[0] - fa[7])
+ - 8 integer parameter/result registers (a[0] - a[7])
+ - 2 registers used by the assembly code to in-place construct its own stack
+ frame.
+ - frame pointer (a[8])
+ - return address (a[9])
+
+ void ffi_call_asm (size_t *stackargs, struct call_context *regargs,
+ void (*fn)(void), void *closure); */
+
+#define FRAME_LEN (8 * FLTS + 10 * PTRS)
+
+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 5, FRAME_LEN # Interim CFA based on a1.
+ SARG $fp, $a1, FRAME_LEN - 2*PTRS
+ .cfi_offset 22, -2*PTRS
+ SARG $ra, $a1, FRAME_LEN - 1*PTRS
+ .cfi_offset 1, -1*PTRS
+
+ addi.d $fp, $a1, FRAME_LEN
+ move $sp, $a0
+ .cfi_def_cfa 22, 0 # Our frame is fully set up.
+
+ # Load arguments.
+ move $t1, $a2
+ move $t2, $a3
+
+#if FLTS
+ FLARG $fa0, $fp, -FRAME_LEN+0*FLTS
+ FLARG $fa1, $fp, -FRAME_LEN+1*FLTS
+ FLARG $fa2, $fp, -FRAME_LEN+2*FLTS
+ FLARG $fa3, $fp, -FRAME_LEN+3*FLTS
+ FLARG $fa4, $fp, -FRAME_LEN+4*FLTS
+ FLARG $fa5, $fp, -FRAME_LEN+5*FLTS
+ FLARG $fa6, $fp, -FRAME_LEN+6*FLTS
+ FLARG $fa7, $fp, -FRAME_LEN+7*FLTS
+#endif
+
+ LARG $a0, $fp, -FRAME_LEN+8*FLTS+0*PTRS
+ LARG $a1, $fp, -FRAME_LEN+8*FLTS+1*PTRS
+ LARG $a2, $fp, -FRAME_LEN+8*FLTS+2*PTRS
+ LARG $a3, $fp, -FRAME_LEN+8*FLTS+3*PTRS
+ LARG $a4, $fp, -FRAME_LEN+8*FLTS+4*PTRS
+ LARG $a5, $fp, -FRAME_LEN+8*FLTS+5*PTRS
+ LARG $a6, $fp, -FRAME_LEN+8*FLTS+6*PTRS
+ LARG $a7, $fp, -FRAME_LEN+8*FLTS+7*PTRS
+
+ /* Call */
+ jirl $ra, $t1, 0
+
+#if FLTS
+ /* Save return values - only a0/a1 (fa0/fa1) are used. */
+ FSARG $fa0, $fp, -FRAME_LEN+0*FLTS
+ FSARG $fa1, $fp, -FRAME_LEN+1*FLTS
+#endif
+
+ SARG $a0, $fp, -FRAME_LEN+8*FLTS+0*PTRS
+ SARG $a1, $fp, -FRAME_LEN+8*FLTS+1*PTRS
+
+ /* Restore and return. */
+ addi.d $sp, $fp, -FRAME_LEN
+ .cfi_def_cfa 3, FRAME_LEN
+ LARG $ra, $fp, -1*PTRS
+ .cfi_restore 1
+ LARG $fp, $fp, -2*PTRS
+ .cfi_restore 22
+ jr $ra
+ .cfi_endproc
+ .size ffi_call_asm, .-ffi_call_asm
+
+
+/* ffi_closure_asm. Expects address of the passed-in ffi_closure in t0.
+ 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.d $sp, $sp, -FRAME_LEN
+ .cfi_def_cfa_offset FRAME_LEN
+
+ /* Make a frame. */
+ SARG $fp, $sp, FRAME_LEN - 2*PTRS
+ .cfi_offset 22, -2*PTRS
+ SARG $ra, $sp, FRAME_LEN - 1*PTRS
+ .cfi_offset 1, -1*PTRS
+ addi.d $fp, $sp, FRAME_LEN
+
+ /* Save arguments. */
+#if FLTS
+ FSARG $fa0, $sp, 0*FLTS
+ FSARG $fa1, $sp, 1*FLTS
+ FSARG $fa2, $sp, 2*FLTS
+ FSARG $fa3, $sp, 3*FLTS
+ FSARG $fa4, $sp, 4*FLTS
+ FSARG $fa5, $sp, 5*FLTS
+ FSARG $fa6, $sp, 6*FLTS
+ FSARG $fa7, $sp, 7*FLTS
+#endif
+
+ SARG $a0, $sp, 8*FLTS+0*PTRS
+ SARG $a1, $sp, 8*FLTS+1*PTRS
+ SARG $a2, $sp, 8*FLTS+2*PTRS
+ SARG $a3, $sp, 8*FLTS+3*PTRS
+ SARG $a4, $sp, 8*FLTS+4*PTRS
+ SARG $a5, $sp, 8*FLTS+5*PTRS
+ SARG $a6, $sp, 8*FLTS+6*PTRS
+ SARG $a7, $sp, 8*FLTS+7*PTRS
+
+ /* Enter C */
+ LARG $a0, $t0, FFI_TRAMPOLINE_SIZE+0*PTRS
+ LARG $a1, $t0, FFI_TRAMPOLINE_SIZE+1*PTRS
+ LARG $a2, $t0, FFI_TRAMPOLINE_SIZE+2*PTRS
+ addi.d $a3, $sp, FRAME_LEN
+ move $a4, $sp
+
+ bl ffi_closure_inner
+
+ /* Return values. */
+#if FLTS
+ FLARG $fa0, $sp, 0*FLTS
+ FLARG $fa1, $sp, 1*FLTS
+#endif
+
+ LARG $a0, $sp, 8*FLTS+0*PTRS
+ LARG $a1, $sp, 8*FLTS+1*PTRS
+
+ /* Restore and return. */
+ LARG $ra, $sp, FRAME_LEN-1*PTRS
+ .cfi_restore 1
+ LARG $fp, $sp, FRAME_LEN-2*PTRS
+ .cfi_restore 22
+ addi.d $sp, $sp, FRAME_LEN
+ .cfi_def_cfa_offset 0
+ jr $ra
+ .cfi_endproc
+ .size ffi_closure_asm, .-ffi_closure_asm
+
+/* Static trampoline code table, in which each element is a trampoline.
+
+ The trampoline clobbers t0 and t1, but we don't save them on the stack
+ because our psABI explicitly says they are scratch registers, at least for
+ ELF. Our dynamic trampoline is already clobbering them anyway.
+
+ The trampoline has two parameters - target code to jump to and data for
+ the target code. The trampoline extracts the parameters from its parameter
+ block (see tramp_table_map()). The trampoline saves the data address in
+ t0 and jumps to the target code. As ffi_closure_asm() already expects the
+ data address to be in t0, we don't need a "ffi_closure_asm_alt". */
+
+#if defined(FFI_EXEC_STATIC_TRAMP)
+ .align 16
+ .globl trampoline_code_table
+ .hidden trampoline_code_table
+ .type trampoline_code_table, @function
+
+trampoline_code_table:
+
+ .rept 65536 / 16
+ pcaddu12i $t1, 16 # 65536 >> 12
+ ld.d $t0, $t1, 0
+ ld.d $t1, $t1, 8
+ jirl $zero, $t1, 0
+ .endr
+ .size trampoline_code_table, .-trampoline_code_table
+
+ .align 2
+#endif
+
+/* 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.d $sp, $sp, -FRAME_LEN
+ .cfi_def_cfa_offset FRAME_LEN
+
+ /* Make a frame. */
+ SARG $fp, $sp, FRAME_LEN - 2*PTRS
+ .cfi_offset 22, -2*PTRS
+ SARG $ra, $sp, FRAME_LEN - 1*PTRS
+ .cfi_offset 1, -1*PTRS
+ addi.d $fp, $sp, FRAME_LEN
+
+ /* Save arguments. */
+#if FLTS
+ FSARG $fa0, $sp, 0*FLTS
+ FSARG $fa1, $sp, 1*FLTS
+ FSARG $fa2, $sp, 2*FLTS
+ FSARG $fa3, $sp, 3*FLTS
+ FSARG $fa4, $sp, 4*FLTS
+ FSARG $fa5, $sp, 5*FLTS
+ FSARG $fa6, $sp, 6*FLTS
+ FSARG $fa7, $sp, 7*FLTS
+#endif
+
+ SARG $a0, $sp, 8*FLTS+0*PTRS
+ SARG $a1, $sp, 8*FLTS+1*PTRS
+ SARG $a2, $sp, 8*FLTS+2*PTRS
+ SARG $a3, $sp, 8*FLTS+3*PTRS
+ SARG $a4, $sp, 8*FLTS+4*PTRS
+ SARG $a5, $sp, 8*FLTS+5*PTRS
+ SARG $a6, $sp, 8*FLTS+6*PTRS
+ SARG $a7, $sp, 8*FLTS+7*PTRS
+
+ /* Enter C */
+ LARG $a0, $t2, 1*PTRS
+ LARG $a1, $t2, 2*PTRS
+ move $a2, $t2
+ addi.d $a3, $sp, FRAME_LEN
+ move $a4, $sp
+
+ bl ffi_closure_inner
+
+ /* Return values. */
+#if FLTS
+ FLARG $fa0, $sp, 0*FLTS
+ FLARG $fa1, $sp, 1*FLTS
+#endif
+
+ LARG $a0, $sp, 8*FLTS+0*PTRS
+ LARG $a1, $sp, 8*FLTS+1*PTRS
+
+ /* Restore and return. */
+ LARG $ra, $sp, FRAME_LEN-1*PTRS
+ .cfi_restore 1
+ LARG $fp, $sp, FRAME_LEN-2*PTRS
+ .cfi_restore 22
+ addi.d $sp, $sp, FRAME_LEN
+ .cfi_def_cfa_offset 0
+ jr $ra
+ .cfi_endproc
+ .size ffi_go_closure_asm, .-ffi_go_closure_asm
+
+#if defined __ELF__ && defined __linux__
+ .section .note.GNU-stack,"",%progbits
+#endif