mirror of
https://github.com/partic2/libffi
synced 2026-11-09 17:47:19 +00:00
Merge branch 'rth7680-go-closure'
This commit is contained in:
+10
-16
@@ -36,9 +36,9 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \
|
||||
src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c \
|
||||
src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \
|
||||
src/sparc/v9.S src/sparc/ffitarget.h src/sparc/ffi.c \
|
||||
src/x86/darwin64.S src/x86/ffi.c src/x86/sysv.S \
|
||||
src/x86/win32.S src/x86/darwin.S src/x86/win64.S \
|
||||
src/x86/freebsd.S src/x86/ffi64.c src/x86/unix64.S \
|
||||
src/sparc/ffi64.c src/x86/darwin64.S src/x86/ffi.c src/x86/sysv.S \
|
||||
src/x86/darwin.S src/x86/ffiw64.c src/x86/win64.S \
|
||||
src/x86/ffi64.c src/x86/unix64.S \
|
||||
src/x86/ffitarget.h src/pa/ffitarget.h src/pa/ffi.c \
|
||||
src/pa/linux.S src/pa/hpux32.S src/frv/ffi.c src/bfin/ffi.c \
|
||||
src/bfin/ffitarget.h src/bfin/sysv.S src/frv/eabi.S \
|
||||
@@ -48,9 +48,9 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \
|
||||
src/xtensa/ffitarget.h src/xtensa/ffi.c src/xtensa/sysv.S \
|
||||
ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \
|
||||
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \
|
||||
m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \
|
||||
m4/ltversion.m4 src/debug.c msvcc.sh \
|
||||
generate-darwin-source-and-headers.py \
|
||||
libffi.xcodeproj/project.pbxproj src/arm/trampoline.S \
|
||||
libffi.xcodeproj/project.pbxproj \
|
||||
libtool-ldflags ChangeLog.libffi-3.1
|
||||
|
||||
info_TEXINFOS = doc/libffi.texi
|
||||
@@ -126,25 +126,22 @@ if BFIN
|
||||
nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S
|
||||
endif
|
||||
if X86
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S src/x86/win32.S
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S
|
||||
endif
|
||||
if X86_FREEBSD
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/freebsd.S src/x86/win32.S
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S
|
||||
endif
|
||||
if X86_WIN32
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win32.S
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S
|
||||
endif
|
||||
if X86_WIN64
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win64.S
|
||||
nodist_libffi_la_SOURCES += src/x86/ffiw64.c src/x86/win64.S
|
||||
endif
|
||||
if X86_DARWIN
|
||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S
|
||||
if X86_DARWIN32
|
||||
nodist_libffi_la_SOURCES += src/x86/win32.S
|
||||
endif
|
||||
endif
|
||||
if SPARC
|
||||
nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S
|
||||
nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/ffi64.c src/sparc/v8.S src/sparc/v9.S
|
||||
endif
|
||||
if ALPHA
|
||||
nodist_libffi_la_SOURCES += src/alpha/ffi.c src/alpha/osf.S
|
||||
@@ -193,9 +190,6 @@ nodist_libffi_la_SOURCES += src/arc/arcompact.S src/arc/ffi.c
|
||||
endif
|
||||
if ARM
|
||||
nodist_libffi_la_SOURCES += src/arm/sysv.S src/arm/ffi.c
|
||||
if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
nodist_libffi_la_SOURCES += src/arm/trampoline.S
|
||||
endif
|
||||
endif
|
||||
if AVR32
|
||||
nodist_libffi_la_SOURCES += src/avr32/sysv.S src/avr32/ffi.c
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Status
|
||||
======
|
||||
|
||||
libffi-3.2.1 was released on November 12, 2014. Check the libffi web
|
||||
libffi-4?? was released on TBD. Check the libffi web
|
||||
page for updates: <URL:http://sourceware.org/libffi/>.
|
||||
|
||||
|
||||
@@ -182,6 +182,9 @@ History
|
||||
|
||||
See the git log for details at http://github.com/atgreen/libffi.
|
||||
|
||||
4.0 TBD
|
||||
New API in support of GO closures.
|
||||
|
||||
3.2.1 Nov-12-14
|
||||
Build fix for non-iOS AArch64 targets.
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ dnl Process this with autoconf to create configure
|
||||
|
||||
AC_PREREQ(2.68)
|
||||
|
||||
AC_INIT([libffi], [3.2.1], [http://github.com/atgreen/libffi/issues])
|
||||
AC_INIT([libffi], [3.99999], [http://github.com/atgreen/libffi/issues])
|
||||
AC_CONFIG_HEADERS([fficonfig.h])
|
||||
|
||||
AC_CANONICAL_SYSTEM
|
||||
|
||||
@@ -428,6 +428,22 @@ ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
|
||||
|
||||
#endif /* FFI_CLOSURES */
|
||||
|
||||
#if FFI_GO_CLOSURES
|
||||
|
||||
typedef struct {
|
||||
void *tramp;
|
||||
ffi_cif *cif;
|
||||
void (*fun)(ffi_cif*,void*,void**,void*);
|
||||
} ffi_go_closure;
|
||||
|
||||
ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*));
|
||||
|
||||
void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure);
|
||||
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
|
||||
/* ---- Public interface definition -------------------------------------- */
|
||||
|
||||
ffi_status ffi_prep_cif(ffi_cif *cif,
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi_cfi.h - Copyright (c) 2014 Red Hat, Inc.
|
||||
|
||||
Conditionally assemble cfi directives. Only necessary for building libffi.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef FFI_CFI_H
|
||||
#define FFI_CFI_H
|
||||
|
||||
#ifdef HAVE_AS_CFI_PSEUDO_OP
|
||||
|
||||
# define cfi_startproc .cfi_startproc
|
||||
# define cfi_endproc .cfi_endproc
|
||||
# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off
|
||||
# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
|
||||
# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off
|
||||
# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
|
||||
# define cfi_offset(reg, off) .cfi_offset reg, off
|
||||
# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
|
||||
# define cfi_register(r1, r2) .cfi_register r1, r2
|
||||
# define cfi_return_column(reg) .cfi_return_column reg
|
||||
# define cfi_restore(reg) .cfi_restore reg
|
||||
# define cfi_same_value(reg) .cfi_same_value reg
|
||||
# define cfi_undefined(reg) .cfi_undefined reg
|
||||
# define cfi_remember_state .cfi_remember_state
|
||||
# define cfi_restore_state .cfi_restore_state
|
||||
# define cfi_window_save .cfi_window_save
|
||||
# define cfi_personality(enc, exp) .cfi_personality enc, exp
|
||||
# define cfi_lsda(enc, exp) .cfi_lsda enc, exp
|
||||
# define cfi_escape(...) .cfi_escape __VA_ARGS__
|
||||
|
||||
#else
|
||||
|
||||
# define cfi_startproc
|
||||
# define cfi_endproc
|
||||
# define cfi_def_cfa(reg, off)
|
||||
# define cfi_def_cfa_register(reg)
|
||||
# define cfi_def_cfa_offset(off)
|
||||
# define cfi_adjust_cfa_offset(off)
|
||||
# define cfi_offset(reg, off)
|
||||
# define cfi_rel_offset(reg, off)
|
||||
# define cfi_register(r1, r2)
|
||||
# define cfi_return_column(reg)
|
||||
# define cfi_restore(reg)
|
||||
# define cfi_same_value(reg)
|
||||
# define cfi_undefined(reg)
|
||||
# define cfi_remember_state
|
||||
# define cfi_restore_state
|
||||
# define cfi_window_save
|
||||
# define cfi_personality(enc, exp)
|
||||
# define cfi_lsda(enc, exp)
|
||||
# define cfi_escape(...)
|
||||
|
||||
#endif /* HAVE_AS_CFI_PSEUDO_OP */
|
||||
#endif /* FFI_CFI_H */
|
||||
+661
-930
File diff suppressed because it is too large
Load Diff
@@ -42,22 +42,20 @@ typedef enum ffi_abi
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_TRAMPOLINE_SIZE 36
|
||||
#define FFI_TRAMPOLINE_SIZE 24
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
/* ---- Internal ---- */
|
||||
|
||||
#if defined (__APPLE__)
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags; unsigned aarch64_nfixedargs
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs
|
||||
#else
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags
|
||||
/* iOS reserves x18 for the system. Disable Go closures until
|
||||
a new static chain is chosen. */
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#endif
|
||||
|
||||
#define AARCH64_FFI_WITH_V_BIT 0
|
||||
|
||||
#define AARCH64_N_XREG 32
|
||||
#define AARCH64_N_VREG 32
|
||||
#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 + AARCH64_N_VREG * 16)
|
||||
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
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 AARCH64_RET_VOID 0
|
||||
#define AARCH64_RET_INT64 1
|
||||
#define AARCH64_RET_INT128 2
|
||||
|
||||
#define AARCH64_RET_UNUSED3 3
|
||||
#define AARCH64_RET_UNUSED4 4
|
||||
#define AARCH64_RET_UNUSED5 5
|
||||
#define AARCH64_RET_UNUSED6 6
|
||||
#define AARCH64_RET_UNUSED7 7
|
||||
|
||||
/* Note that FFI_TYPE_FLOAT == 2, _DOUBLE == 3, _LONGDOUBLE == 4,
|
||||
so _S4 through _Q1 are layed out as (TYPE * 4) + (4 - COUNT). */
|
||||
#define AARCH64_RET_S4 8
|
||||
#define AARCH64_RET_S3 9
|
||||
#define AARCH64_RET_S2 10
|
||||
#define AARCH64_RET_S1 11
|
||||
|
||||
#define AARCH64_RET_D4 12
|
||||
#define AARCH64_RET_D3 13
|
||||
#define AARCH64_RET_D2 14
|
||||
#define AARCH64_RET_D1 15
|
||||
|
||||
#define AARCH64_RET_Q4 16
|
||||
#define AARCH64_RET_Q3 17
|
||||
#define AARCH64_RET_Q2 18
|
||||
#define AARCH64_RET_Q1 19
|
||||
|
||||
/* Note that each of the sub-64-bit integers gets two entries. */
|
||||
#define AARCH64_RET_UINT8 20
|
||||
#define AARCH64_RET_UINT16 22
|
||||
#define AARCH64_RET_UINT32 24
|
||||
|
||||
#define AARCH64_RET_SINT8 26
|
||||
#define AARCH64_RET_SINT16 28
|
||||
#define AARCH64_RET_SINT32 30
|
||||
|
||||
#define AARCH64_RET_MASK 31
|
||||
|
||||
#define AARCH64_RET_IN_MEM (1 << 5)
|
||||
#define AARCH64_RET_NEED_COPY (1 << 6)
|
||||
|
||||
#define AARCH64_FLAG_ARG_V_BIT 7
|
||||
#define AARCH64_FLAG_ARG_V (1 << AARCH64_FLAG_ARG_V_BIT)
|
||||
|
||||
#define N_X_ARG_REG 8
|
||||
#define N_V_ARG_REG 8
|
||||
#define CALL_CONTEXT_SIZE (N_V_ARG_REG * 16 + N_X_ARG_REG * 8)
|
||||
+330
-265
@@ -22,6 +22,8 @@ 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"
|
||||
|
||||
#ifdef HAVE_MACHINE_ASM_H
|
||||
#include <machine/asm.h>
|
||||
@@ -37,297 +39,360 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
|
||||
#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
|
||||
#define cfi_restore(reg) .cfi_restore reg
|
||||
#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
|
||||
|
||||
.text
|
||||
.globl CNAME(ffi_call_SYSV)
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_call_SYSV), #function
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
.align 2
|
||||
#ifdef __AARCH64EB__
|
||||
# define BE(X) X
|
||||
#else
|
||||
# define BE(X) 0
|
||||
#endif
|
||||
|
||||
/* ffi_call_SYSV()
|
||||
.text
|
||||
.align 4
|
||||
|
||||
Create a stack frame, setup an argument context, call the callee
|
||||
and extract the result.
|
||||
|
||||
The maximum required argument stack size is provided,
|
||||
ffi_call_SYSV() allocates that stack space then calls the
|
||||
prepare_fn to populate register context and stack. The
|
||||
argument passing registers are loaded from the register
|
||||
context and the callee called, on return the register passing
|
||||
register are saved back to the context. Our caller will
|
||||
extract the return value from the final state of the saved
|
||||
register context.
|
||||
|
||||
Prototype:
|
||||
|
||||
extern unsigned
|
||||
ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
|
||||
extended_cif *),
|
||||
struct call_context *context,
|
||||
extended_cif *,
|
||||
size_t required_stack_size,
|
||||
void (*fn)(void));
|
||||
/* ffi_call_SYSV
|
||||
extern void ffi_call_SYSV (void *stack, void *frame,
|
||||
void (*fn)(void), void *rvalue,
|
||||
int flags, void *closure);
|
||||
|
||||
Therefore on entry we have:
|
||||
|
||||
x0 prepare_fn
|
||||
x1 &context
|
||||
x2 &ecif
|
||||
x3 bytes
|
||||
x4 fn
|
||||
x0 stack
|
||||
x1 frame
|
||||
x2 fn
|
||||
x3 rvalue
|
||||
x4 flags
|
||||
x5 closure
|
||||
*/
|
||||
|
||||
This function uses the following stack frame layout:
|
||||
|
||||
==
|
||||
saved x30(lr)
|
||||
x29(fp)-> saved x29(fp)
|
||||
saved x24
|
||||
saved x23
|
||||
saved x22
|
||||
sp' -> saved x21
|
||||
...
|
||||
sp -> (constructed callee stack arguments)
|
||||
==
|
||||
|
||||
Voila! */
|
||||
|
||||
#define ffi_call_SYSV_FS (8 * 4)
|
||||
|
||||
.cfi_startproc
|
||||
cfi_startproc
|
||||
CNAME(ffi_call_SYSV):
|
||||
stp x29, x30, [sp, #-16]!
|
||||
cfi_adjust_cfa_offset (16)
|
||||
cfi_rel_offset (x29, 0)
|
||||
cfi_rel_offset (x30, 8)
|
||||
/* Use a stack frame allocated by our caller. */
|
||||
cfi_def_cfa(x1, 32);
|
||||
stp x29, x30, [x1]
|
||||
mov x29, x1
|
||||
mov sp, x0
|
||||
cfi_def_cfa_register(x29)
|
||||
cfi_rel_offset (x29, 0)
|
||||
cfi_rel_offset (x30, 8)
|
||||
|
||||
mov x29, sp
|
||||
cfi_def_cfa_register (x29)
|
||||
sub sp, sp, #ffi_call_SYSV_FS
|
||||
|
||||
stp x21, x22, [sp, #0]
|
||||
cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
|
||||
cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
|
||||
|
||||
stp x23, x24, [sp, #16]
|
||||
cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
|
||||
cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
|
||||
|
||||
mov x21, x1
|
||||
mov x22, x2
|
||||
mov x24, x4
|
||||
|
||||
/* Allocate the stack space for the actual arguments, many
|
||||
arguments will be passed in registers, but we assume
|
||||
worst case and allocate sufficient stack for ALL of
|
||||
the arguments. */
|
||||
sub sp, sp, x3
|
||||
|
||||
/* unsigned (*prepare_fn) (struct call_context *context,
|
||||
unsigned char *stack, extended_cif *ecif);
|
||||
*/
|
||||
mov x23, x0
|
||||
mov x0, x1
|
||||
mov x1, sp
|
||||
/* x2 already in place */
|
||||
blr x23
|
||||
|
||||
/* Preserve the flags returned. */
|
||||
mov x23, x0
|
||||
|
||||
/* Figure out if we should touch the vector registers. */
|
||||
tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
|
||||
|
||||
/* Load the vector argument passing registers. */
|
||||
ldp q0, q1, [x21, #8*32 + 0]
|
||||
ldp q2, q3, [x21, #8*32 + 32]
|
||||
ldp q4, q5, [x21, #8*32 + 64]
|
||||
ldp q6, q7, [x21, #8*32 + 96]
|
||||
1:
|
||||
/* Load the core argument passing registers. */
|
||||
ldp x0, x1, [x21, #0]
|
||||
ldp x2, x3, [x21, #16]
|
||||
ldp x4, x5, [x21, #32]
|
||||
ldp x6, x7, [x21, #48]
|
||||
|
||||
/* Don't forget x8 which may be holding the address of a return buffer.
|
||||
*/
|
||||
ldr x8, [x21, #8*8]
|
||||
|
||||
blr x24
|
||||
|
||||
/* Save the core argument passing registers. */
|
||||
stp x0, x1, [x21, #0]
|
||||
stp x2, x3, [x21, #16]
|
||||
stp x4, x5, [x21, #32]
|
||||
stp x6, x7, [x21, #48]
|
||||
|
||||
/* Note nothing useful ever comes back in x8! */
|
||||
|
||||
/* Figure out if we should touch the vector registers. */
|
||||
tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
|
||||
|
||||
/* Save the vector argument passing registers. */
|
||||
stp q0, q1, [x21, #8*32 + 0]
|
||||
stp q2, q3, [x21, #8*32 + 32]
|
||||
stp q4, q5, [x21, #8*32 + 64]
|
||||
stp q6, q7, [x21, #8*32 + 96]
|
||||
1:
|
||||
/* All done, unwind our stack frame. */
|
||||
ldp x21, x22, [x29, # - ffi_call_SYSV_FS]
|
||||
cfi_restore (x21)
|
||||
cfi_restore (x22)
|
||||
|
||||
ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16]
|
||||
cfi_restore (x23)
|
||||
cfi_restore (x24)
|
||||
|
||||
mov sp, x29
|
||||
cfi_def_cfa_register (sp)
|
||||
|
||||
ldp x29, x30, [sp], #16
|
||||
cfi_adjust_cfa_offset (-16)
|
||||
cfi_restore (x29)
|
||||
cfi_restore (x30)
|
||||
|
||||
ret
|
||||
|
||||
.cfi_endproc
|
||||
#ifdef __ELF__
|
||||
.size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
|
||||
mov x9, x2 /* save fn */
|
||||
mov x8, x3 /* install structure return */
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
mov x18, x5 /* install static chain */
|
||||
#endif
|
||||
stp x3, x4, [x29, #16] /* save rvalue and flags */
|
||||
|
||||
#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
|
||||
/* Load the vector argument passing registers, if necessary. */
|
||||
tbz w4, #AARCH64_FLAG_ARG_V_BIT, 1f
|
||||
ldp q0, q1, [sp, #0]
|
||||
ldp q2, q3, [sp, #32]
|
||||
ldp q4, q5, [sp, #64]
|
||||
ldp q6, q7, [sp, #96]
|
||||
1:
|
||||
/* Load the core argument passing registers, including
|
||||
the structure return pointer. */
|
||||
ldp x0, x1, [sp, #16*N_V_ARG_REG + 0]
|
||||
ldp x2, x3, [sp, #16*N_V_ARG_REG + 16]
|
||||
ldp x4, x5, [sp, #16*N_V_ARG_REG + 32]
|
||||
ldp x6, x7, [sp, #16*N_V_ARG_REG + 48]
|
||||
|
||||
/* Deallocate the context, leaving the stacked arguments. */
|
||||
add sp, sp, #CALL_CONTEXT_SIZE
|
||||
|
||||
blr x9 /* call fn */
|
||||
|
||||
ldp x3, x4, [x29, #16] /* reload rvalue and flags */
|
||||
|
||||
/* Partially deconstruct the stack frame. */
|
||||
mov sp, x29
|
||||
cfi_def_cfa_register (sp)
|
||||
ldp x29, x30, [x29]
|
||||
|
||||
/* Save the return value as directed. */
|
||||
adr x5, 0f
|
||||
and w4, w4, #AARCH64_RET_MASK
|
||||
add x5, x5, x4, lsl #3
|
||||
br x5
|
||||
|
||||
/* Note that each table entry is 2 insns, and thus 8 bytes.
|
||||
For integer data, note that we're storing into ffi_arg
|
||||
and therefore we want to extend to 64 bits; these types
|
||||
have two consecutive entries allocated for them. */
|
||||
.align 4
|
||||
0: ret /* VOID */
|
||||
nop
|
||||
1: str x0, [x3] /* INT64 */
|
||||
ret
|
||||
2: stp x0, x1, [x3] /* INT128 */
|
||||
ret
|
||||
3: brk #1000 /* UNUSED */
|
||||
ret
|
||||
4: brk #1000 /* UNUSED */
|
||||
ret
|
||||
5: brk #1000 /* UNUSED */
|
||||
ret
|
||||
6: brk #1000 /* UNUSED */
|
||||
ret
|
||||
7: brk #1000 /* UNUSED */
|
||||
ret
|
||||
8: st4 { v0.s-v3.s }[0], [x3] /* S4 */
|
||||
ret
|
||||
9: st3 { v0.s-v2.s }[0], [x3] /* S3 */
|
||||
ret
|
||||
10: stp s0, s1, [x3] /* S2 */
|
||||
ret
|
||||
11: str s0, [x3] /* S1 */
|
||||
ret
|
||||
12: st4 { v0.d-v3.d }[0], [x3] /* D4 */
|
||||
ret
|
||||
13: st3 { v0.d-v2.d }[0], [x3] /* D3 */
|
||||
ret
|
||||
14: stp d0, d1, [x3] /* D2 */
|
||||
ret
|
||||
15: str d0, [x3] /* D1 */
|
||||
ret
|
||||
16: str q3, [x3, #48] /* Q4 */
|
||||
nop
|
||||
17: str q2, [x3, #32] /* Q3 */
|
||||
nop
|
||||
18: stp q0, q1, [x3] /* Q2 */
|
||||
ret
|
||||
19: str q0, [x3] /* Q1 */
|
||||
ret
|
||||
20: uxtb w0, w0 /* UINT8 */
|
||||
str x0, [x3]
|
||||
21: ret /* reserved */
|
||||
nop
|
||||
22: uxth w0, w0 /* UINT16 */
|
||||
str x0, [x3]
|
||||
23: ret /* reserved */
|
||||
nop
|
||||
24: mov w0, w0 /* UINT32 */
|
||||
str x0, [x3]
|
||||
25: ret /* reserved */
|
||||
nop
|
||||
26: sxtb x0, w0 /* SINT8 */
|
||||
str x0, [x3]
|
||||
27: ret /* reserved */
|
||||
nop
|
||||
28: sxth x0, w0 /* SINT16 */
|
||||
str x0, [x3]
|
||||
29: ret /* reserved */
|
||||
nop
|
||||
30: sxtw x0, w0 /* SINT32 */
|
||||
str x0, [x3]
|
||||
31: ret /* reserved */
|
||||
nop
|
||||
|
||||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_call_SYSV)
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_call_SYSV), #function
|
||||
.hidden CNAME(ffi_call_SYSV)
|
||||
.size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
|
||||
#endif
|
||||
|
||||
/* ffi_closure_SYSV
|
||||
|
||||
Closure invocation glue. This is the low level code invoked directly by
|
||||
the closure trampoline to setup and call a closure.
|
||||
|
||||
On entry x17 points to a struct trampoline_data, x16 has been clobbered
|
||||
On entry x17 points to a struct ffi_closure, x16 has been clobbered
|
||||
all other registers are preserved.
|
||||
|
||||
We allocate a call context and save the argument passing registers,
|
||||
then invoked the generic C ffi_closure_SYSV_inner() function to do all
|
||||
the real work, on return we load the result passing registers back from
|
||||
the call context.
|
||||
*/
|
||||
|
||||
On entry
|
||||
#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64)
|
||||
|
||||
extern void
|
||||
ffi_closure_SYSV (struct trampoline_data *);
|
||||
.align 4
|
||||
CNAME(ffi_closure_SYSV_V):
|
||||
cfi_startproc
|
||||
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
||||
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
||||
cfi_rel_offset (x29, 0)
|
||||
cfi_rel_offset (x30, 8)
|
||||
|
||||
struct trampoline_data
|
||||
{
|
||||
UINT64 *ffi_closure;
|
||||
UINT64 flags;
|
||||
};
|
||||
/* Save the argument passing vector registers. */
|
||||
stp q0, q1, [sp, #16 + 0]
|
||||
stp q2, q3, [sp, #16 + 32]
|
||||
stp q4, q5, [sp, #16 + 64]
|
||||
stp q6, q7, [sp, #16 + 96]
|
||||
b 0f
|
||||
cfi_endproc
|
||||
|
||||
This function uses the following stack frame layout:
|
||||
|
||||
==
|
||||
saved x30(lr)
|
||||
x29(fp)-> saved x29(fp)
|
||||
saved x22
|
||||
saved x21
|
||||
...
|
||||
sp -> call_context
|
||||
==
|
||||
|
||||
Voila! */
|
||||
|
||||
.text
|
||||
.globl CNAME(ffi_closure_SYSV)
|
||||
#ifdef __APPLE__
|
||||
.align 2
|
||||
#endif
|
||||
.cfi_startproc
|
||||
CNAME(ffi_closure_SYSV):
|
||||
stp x29, x30, [sp, #-16]!
|
||||
cfi_adjust_cfa_offset (16)
|
||||
cfi_rel_offset (x29, 0)
|
||||
cfi_rel_offset (x30, 8)
|
||||
|
||||
mov x29, sp
|
||||
cfi_def_cfa_register (x29)
|
||||
|
||||
sub sp, sp, #ffi_closure_SYSV_FS
|
||||
|
||||
stp x21, x22, [x29, #-16]
|
||||
cfi_rel_offset (x21, -16)
|
||||
cfi_rel_offset (x22, -8)
|
||||
|
||||
/* Load x21 with &call_context. */
|
||||
mov x21, sp
|
||||
/* Preserve our struct trampoline_data * */
|
||||
mov x22, x17
|
||||
|
||||
/* Save the rest of the argument passing registers. */
|
||||
stp x0, x1, [x21, #0]
|
||||
stp x2, x3, [x21, #16]
|
||||
stp x4, x5, [x21, #32]
|
||||
stp x6, x7, [x21, #48]
|
||||
/* Don't forget we may have been given a result scratch pad address.
|
||||
*/
|
||||
str x8, [x21, #64]
|
||||
|
||||
/* Figure out if we should touch the vector registers. */
|
||||
ldr x0, [x22, #8]
|
||||
tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
|
||||
|
||||
/* Save the argument passing vector registers. */
|
||||
stp q0, q1, [x21, #8*32 + 0]
|
||||
stp q2, q3, [x21, #8*32 + 32]
|
||||
stp q4, q5, [x21, #8*32 + 64]
|
||||
stp q6, q7, [x21, #8*32 + 96]
|
||||
1:
|
||||
/* Load &ffi_closure.. */
|
||||
ldr x0, [x22, #0]
|
||||
mov x1, x21
|
||||
/* Compute the location of the stack at the point that the
|
||||
trampoline was called. */
|
||||
add x2, x29, #16
|
||||
|
||||
bl CNAME(ffi_closure_SYSV_inner)
|
||||
|
||||
/* Figure out if we should touch the vector registers. */
|
||||
ldr x0, [x22, #8]
|
||||
tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
|
||||
|
||||
/* Load the result passing vector registers. */
|
||||
ldp q0, q1, [x21, #8*32 + 0]
|
||||
ldp q2, q3, [x21, #8*32 + 32]
|
||||
ldp q4, q5, [x21, #8*32 + 64]
|
||||
ldp q6, q7, [x21, #8*32 + 96]
|
||||
1:
|
||||
/* Load the result passing core registers. */
|
||||
ldp x0, x1, [x21, #0]
|
||||
ldp x2, x3, [x21, #16]
|
||||
ldp x4, x5, [x21, #32]
|
||||
ldp x6, x7, [x21, #48]
|
||||
/* Note nothing useful is returned in x8. */
|
||||
|
||||
/* We are done, unwind our frame. */
|
||||
ldp x21, x22, [x29, #-16]
|
||||
cfi_restore (x21)
|
||||
cfi_restore (x22)
|
||||
|
||||
mov sp, x29
|
||||
cfi_def_cfa_register (sp)
|
||||
|
||||
ldp x29, x30, [sp], #16
|
||||
cfi_adjust_cfa_offset (-16)
|
||||
cfi_restore (x29)
|
||||
cfi_restore (x30)
|
||||
|
||||
ret
|
||||
.cfi_endproc
|
||||
.globl CNAME(ffi_closure_SYSV_V)
|
||||
#ifdef __ELF__
|
||||
.size CNAME(ffi_closure_SYSV), .-CNAME(ffi_closure_SYSV)
|
||||
.type CNAME(ffi_closure_SYSV_V), #function
|
||||
.hidden CNAME(ffi_closure_SYSV_V)
|
||||
.size CNAME(ffi_closure_SYSV_V), . - CNAME(ffi_closure_SYSV_V)
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
cfi_startproc
|
||||
CNAME(ffi_closure_SYSV):
|
||||
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
||||
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
||||
cfi_rel_offset (x29, 0)
|
||||
cfi_rel_offset (x30, 8)
|
||||
0:
|
||||
mov x29, sp
|
||||
|
||||
/* Save the argument passing core registers. */
|
||||
stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
|
||||
stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
|
||||
stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
|
||||
stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
|
||||
|
||||
/* Load ffi_closure_inner arguments. */
|
||||
ldp x0, x1, [x17, #FFI_TRAMPOLINE_SIZE] /* load cif, fn */
|
||||
ldr x2, [x17, #FFI_TRAMPOLINE_SIZE+16] /* load user_data */
|
||||
.Ldo_closure:
|
||||
add x3, sp, #16 /* load context */
|
||||
add x4, sp, #ffi_closure_SYSV_FS /* load stack */
|
||||
add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
|
||||
mov x6, x8 /* load struct_rval */
|
||||
bl CNAME(ffi_closure_SYSV_inner)
|
||||
|
||||
/* Load the return value as directed. */
|
||||
adr x1, 0f
|
||||
and w0, w0, #AARCH64_RET_MASK
|
||||
add x1, x1, x0, lsl #3
|
||||
add x3, sp, #16+CALL_CONTEXT_SIZE
|
||||
br x1
|
||||
|
||||
/* Note that each table entry is 2 insns, and thus 8 bytes. */
|
||||
.align 4
|
||||
0: b 99f /* VOID */
|
||||
nop
|
||||
1: ldr x0, [x3] /* INT64 */
|
||||
b 99f
|
||||
2: ldp x0, x1, [x3] /* INT128 */
|
||||
b 99f
|
||||
3: brk #1000 /* UNUSED */
|
||||
nop
|
||||
4: brk #1000 /* UNUSED */
|
||||
nop
|
||||
5: brk #1000 /* UNUSED */
|
||||
nop
|
||||
6: brk #1000 /* UNUSED */
|
||||
nop
|
||||
7: brk #1000 /* UNUSED */
|
||||
nop
|
||||
8: ldr s3, [x3, #12] /* S4 */
|
||||
nop
|
||||
9: ldr s2, [x2, #8] /* S3 */
|
||||
nop
|
||||
10: ldp s0, s1, [x3] /* S2 */
|
||||
b 99f
|
||||
11: ldr s0, [x3] /* S1 */
|
||||
b 99f
|
||||
12: ldr d3, [x3, #24] /* D4 */
|
||||
nop
|
||||
13: ldr d2, [x3, #16] /* D3 */
|
||||
nop
|
||||
14: ldp d0, d1, [x3] /* D2 */
|
||||
b 99f
|
||||
15: ldr d0, [x3] /* D1 */
|
||||
b 99f
|
||||
16: ldr q3, [x3, #48] /* Q4 */
|
||||
nop
|
||||
17: ldr q2, [x3, #32] /* Q3 */
|
||||
nop
|
||||
18: ldp q0, q1, [x3] /* Q2 */
|
||||
b 99f
|
||||
19: ldr q0, [x3] /* Q1 */
|
||||
b 99f
|
||||
20: ldrb w0, [x3, #BE(7)] /* UINT8 */
|
||||
b 99f
|
||||
21: brk #1000 /* reserved */
|
||||
nop
|
||||
22: ldrh w0, [x3, #BE(6)] /* UINT16 */
|
||||
b 99f
|
||||
23: brk #1000 /* reserved */
|
||||
nop
|
||||
24: ldr w0, [x3, #BE(4)] /* UINT32 */
|
||||
b 99f
|
||||
25: brk #1000 /* reserved */
|
||||
nop
|
||||
26: ldrsb x0, [x3, #BE(7)] /* SINT8 */
|
||||
b 99f
|
||||
27: brk #1000 /* reserved */
|
||||
nop
|
||||
28: ldrsh x0, [x3, #BE(6)] /* SINT16 */
|
||||
b 99f
|
||||
29: brk #1000 /* reserved */
|
||||
nop
|
||||
30: ldrsw x0, [x3, #BE(4)] /* SINT32 */
|
||||
nop
|
||||
31: /* reserved */
|
||||
99: ldp x29, x30, [sp], #ffi_closure_SYSV_FS
|
||||
cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS)
|
||||
cfi_restore (x29)
|
||||
cfi_restore (x30)
|
||||
ret
|
||||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_closure_SYSV)
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_closure_SYSV), #function
|
||||
.hidden CNAME(ffi_closure_SYSV)
|
||||
.size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV)
|
||||
#endif
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
.align 4
|
||||
CNAME(ffi_go_closure_SYSV_V):
|
||||
cfi_startproc
|
||||
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
||||
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
||||
cfi_rel_offset (x29, 0)
|
||||
cfi_rel_offset (x30, 8)
|
||||
|
||||
/* Save the argument passing vector registers. */
|
||||
stp q0, q1, [sp, #16 + 0]
|
||||
stp q2, q3, [sp, #16 + 32]
|
||||
stp q4, q5, [sp, #16 + 64]
|
||||
stp q6, q7, [sp, #16 + 96]
|
||||
b 0f
|
||||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_go_closure_SYSV_V)
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_go_closure_SYSV_V), #function
|
||||
.hidden CNAME(ffi_go_closure_SYSV_V)
|
||||
.size CNAME(ffi_go_closure_SYSV_V), . - CNAME(ffi_go_closure_SYSV_V)
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
cfi_startproc
|
||||
CNAME(ffi_go_closure_SYSV):
|
||||
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
||||
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
||||
cfi_rel_offset (x29, 0)
|
||||
cfi_rel_offset (x30, 8)
|
||||
0:
|
||||
mov x29, sp
|
||||
|
||||
/* Save the argument passing core registers. */
|
||||
stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
|
||||
stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
|
||||
stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
|
||||
stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
|
||||
|
||||
/* Load ffi_closure_inner arguments. */
|
||||
ldp x0, x1, [x18, #8] /* load cif, fn */
|
||||
mov x2, x18 /* load user_data */
|
||||
b .Ldo_closure
|
||||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_go_closure_SYSV)
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_go_closure_SYSV), #function
|
||||
.hidden CNAME(ffi_go_closure_SYSV)
|
||||
.size CNAME(ffi_go_closure_SYSV), . - CNAME(ffi_go_closure_SYSV)
|
||||
#endif
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
|
||||
+334
-101
@@ -1,8 +1,8 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 2012 Anthony Green
|
||||
Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
|
||||
|
||||
Alpha Foreign Function Interface
|
||||
Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
|
||||
|
||||
Alpha Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
#include <stdlib.h>
|
||||
#include "internal.h"
|
||||
|
||||
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
||||
all further uses in this file will refer to the 128-bit type. */
|
||||
@@ -40,135 +41,286 @@
|
||||
# define FFI_TYPE_LONGDOUBLE 4
|
||||
#endif
|
||||
|
||||
extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void))
|
||||
FFI_HIDDEN;
|
||||
extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
|
||||
void *raddr, void (*fn)(void), void *closure)
|
||||
FFI_HIDDEN;
|
||||
extern void ffi_closure_osf(void) FFI_HIDDEN;
|
||||
extern void ffi_go_closure_osf(void) FFI_HIDDEN;
|
||||
|
||||
/* Promote a float value to its in-register double representation.
|
||||
Unlike actually casting to double, this does not trap on NaN. */
|
||||
static inline UINT64 lds(void *ptr)
|
||||
{
|
||||
UINT64 ret;
|
||||
asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ffi_status
|
||||
/* And the reverse. */
|
||||
static inline void sts(void *ptr, UINT64 val)
|
||||
{
|
||||
asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
|
||||
}
|
||||
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
/* Adjust cif->bytes to represent a minimum 6 words for the temporary
|
||||
register argument loading area. */
|
||||
if (cif->bytes < 6*FFI_SIZEOF_ARG)
|
||||
cif->bytes = 6*FFI_SIZEOF_ARG;
|
||||
size_t bytes = 0;
|
||||
int flags, i, avn;
|
||||
ffi_type *rtype, *itype;
|
||||
|
||||
if (cif->abi != FFI_OSF)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
/* Compute the size of the argument area. */
|
||||
for (i = 0, avn = cif->nargs; i < avn; i++)
|
||||
{
|
||||
itype = cif->arg_types[i];
|
||||
switch (itype->type)
|
||||
{
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
/* All take one 8 byte slot. */
|
||||
bytes += 8;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_VOID:
|
||||
case FFI_TYPE_STRUCT:
|
||||
/* Passed by value in N slots. */
|
||||
bytes += ALIGN(itype->size, FFI_SIZEOF_ARG);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
/* _Complex long double passed by reference; others in 2 slots. */
|
||||
if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
|
||||
bytes += 8;
|
||||
else
|
||||
bytes += 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the return type flag */
|
||||
switch (cif->rtype->type)
|
||||
rtype = cif->rtype;
|
||||
switch (rtype->type)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
case FFI_TYPE_VOID:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
cif->flags = cif->rtype->type;
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
|
||||
break;
|
||||
case FFI_TYPE_SINT8:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
|
||||
break;
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
/* 128-bit long double is returned in memory, like a struct. */
|
||||
cif->flags = FFI_TYPE_STRUCT;
|
||||
case FFI_TYPE_STRUCT:
|
||||
/* Passed in memory, with a hidden pointer. */
|
||||
flags = ALPHA_RET_IN_MEM;
|
||||
break;
|
||||
case FFI_TYPE_COMPLEX:
|
||||
itype = rtype->elements[0];
|
||||
switch (itype->type)
|
||||
{
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
|
||||
break;
|
||||
default:
|
||||
if (rtype->size <= 8)
|
||||
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
|
||||
else
|
||||
flags = ALPHA_RET_IN_MEM;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
|
||||
cif->flags = flags;
|
||||
|
||||
/* Include the hidden structure pointer in args requirement. */
|
||||
if (flags == ALPHA_RET_IN_MEM)
|
||||
bytes += 8;
|
||||
/* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
|
||||
if (bytes < 6*8)
|
||||
bytes = 6*8;
|
||||
cif->bytes = bytes;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
static unsigned long
|
||||
extend_basic_type(void *valp, int type, int argn)
|
||||
{
|
||||
unsigned long *stack, *argp;
|
||||
long i, avn;
|
||||
switch (type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
return *(SINT8 *)valp;
|
||||
case FFI_TYPE_UINT8:
|
||||
return *(UINT8 *)valp;
|
||||
case FFI_TYPE_SINT16:
|
||||
return *(SINT16 *)valp;
|
||||
case FFI_TYPE_UINT16:
|
||||
return *(UINT16 *)valp;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
if (argn < 6)
|
||||
return lds(valp);
|
||||
/* FALLTHRU */
|
||||
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
/* Note that unsigned 32-bit quantities are sign extended. */
|
||||
return *(SINT32 *)valp;
|
||||
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
return *(UINT64 *)valp;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
unsigned long *argp;
|
||||
long i, avn, argn, flags = cif->flags;
|
||||
ffi_type **arg_types;
|
||||
|
||||
void *frame;
|
||||
|
||||
/* If the return value is a struct and we don't have a return
|
||||
value address then we need to make one. */
|
||||
if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT)
|
||||
if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
|
||||
rvalue = alloca(cif->rtype->size);
|
||||
|
||||
/* Allocate the space for the arguments, plus 4 words of temp
|
||||
space for ffi_call_osf. */
|
||||
argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
|
||||
argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
|
||||
frame += cif->bytes;
|
||||
|
||||
if (cif->flags == FFI_TYPE_STRUCT)
|
||||
*(void **) argp++ = rvalue;
|
||||
argn = 0;
|
||||
if (flags == ALPHA_RET_IN_MEM)
|
||||
argp[argn++] = (unsigned long)rvalue;
|
||||
|
||||
i = 0;
|
||||
avn = cif->nargs;
|
||||
arg_types = cif->arg_types;
|
||||
|
||||
while (i < avn)
|
||||
for (i = 0, avn = cif->nargs; i < avn; i++)
|
||||
{
|
||||
size_t size = (*arg_types)->size;
|
||||
ffi_type *ty = arg_types[i];
|
||||
void *valp = avalue[i];
|
||||
int type = ty->type;
|
||||
size_t size;
|
||||
|
||||
switch ((*arg_types)->type)
|
||||
switch (type)
|
||||
{
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT8:
|
||||
*(SINT64 *) argp = *(SINT8 *)(* avalue);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
*(SINT64 *) argp = *(UINT8 *)(* avalue);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
*(SINT64 *) argp = *(SINT16 *)(* avalue);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT16:
|
||||
*(SINT64 *) argp = *(UINT16 *)(* avalue);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
/* Note that unsigned 32-bit quantities are sign extended. */
|
||||
*(SINT64 *) argp = *(SINT32 *)(* avalue);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
*(UINT64 *) argp = *(UINT64 *)(* avalue);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
if (argp - stack < 6)
|
||||
{
|
||||
/* Note the conversion -- all the fp regs are loaded as
|
||||
doubles. The in-register format is the same. */
|
||||
*(double *) argp = *(float *)(* avalue);
|
||||
}
|
||||
else
|
||||
*(float *) argp = *(float *)(* avalue);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
*(double *) argp = *(double *)(* avalue);
|
||||
argp[argn] = extend_basic_type(valp, type, argn);
|
||||
argn++;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
/* 128-bit long double is passed by reference. */
|
||||
*(long double **) argp = (long double *)(* avalue);
|
||||
size = sizeof (long double *);
|
||||
by_reference:
|
||||
/* Note that 128-bit long double is passed by reference. */
|
||||
argp[argn++] = (unsigned long)valp;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_VOID:
|
||||
case FFI_TYPE_STRUCT:
|
||||
memcpy(argp, *avalue, (*arg_types)->size);
|
||||
size = ty->size;
|
||||
memcpy(argp + argn, valp, size);
|
||||
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
type = ty->elements[0]->type;
|
||||
if (type == FFI_TYPE_LONGDOUBLE)
|
||||
goto by_reference;
|
||||
|
||||
/* Most complex types passed as two separate arguments. */
|
||||
size = ty->elements[0]->size;
|
||||
argp[argn] = extend_basic_type(valp, type, argn);
|
||||
argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
|
||||
argn += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
i++, arg_types++, avalue++;
|
||||
}
|
||||
|
||||
ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
|
||||
flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
|
||||
ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
@@ -204,39 +356,56 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*))
|
||||
{
|
||||
if (cif->abi != FFI_OSF)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
closure->tramp = (void *)ffi_go_closure_osf;
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
long FFI_HIDDEN
|
||||
ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
|
||||
ffi_closure_osf_inner (ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *rvalue, unsigned long *argp)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
void **avalue;
|
||||
ffi_type **arg_types;
|
||||
long i, avn, argn;
|
||||
long i, avn, argn, flags;
|
||||
|
||||
cif = closure->cif;
|
||||
avalue = alloca(cif->nargs * sizeof(void *));
|
||||
|
||||
flags = cif->flags;
|
||||
argn = 0;
|
||||
|
||||
/* Copy the caller's structure return address to that the closure
|
||||
returns the data directly to the caller. */
|
||||
if (cif->flags == FFI_TYPE_STRUCT)
|
||||
if (flags == ALPHA_RET_IN_MEM)
|
||||
{
|
||||
rvalue = (void *) argp[0];
|
||||
argn = 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
avn = cif->nargs;
|
||||
arg_types = cif->arg_types;
|
||||
|
||||
/* Grab the addresses of the arguments from the stack frame. */
|
||||
while (i < avn)
|
||||
{
|
||||
size_t size = arg_types[i]->size;
|
||||
|
||||
switch (arg_types[i]->type)
|
||||
/* Grab the addresses of the arguments from the stack frame. */
|
||||
for (i = 0, avn = cif->nargs; i < avn; i++)
|
||||
{
|
||||
ffi_type *ty = arg_types[i];
|
||||
int type = ty->type;
|
||||
void *valp = &argp[argn];
|
||||
size_t size;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
@@ -246,43 +415,107 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
argn += 1;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_VOID:
|
||||
case FFI_TYPE_STRUCT:
|
||||
avalue[i] = &argp[argn];
|
||||
size = ty->size;
|
||||
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
/* Floats coming from registers need conversion from double
|
||||
back to float format. */
|
||||
if (argn < 6)
|
||||
{
|
||||
/* Floats coming from registers need conversion from double
|
||||
back to float format. */
|
||||
*(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
|
||||
avalue[i] = &argp[argn - 6];
|
||||
valp = &argp[argn - 6];
|
||||
sts(valp, argp[argn - 6]);
|
||||
}
|
||||
else
|
||||
avalue[i] = &argp[argn];
|
||||
argn += 1;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
|
||||
if (argn < 6)
|
||||
valp = &argp[argn - 6];
|
||||
argn += 1;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
by_reference:
|
||||
/* 128-bit long double is passed by reference. */
|
||||
avalue[i] = (long double *) argp[argn];
|
||||
size = sizeof (long double *);
|
||||
valp = (void *)argp[argn];
|
||||
argn += 1;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
type = ty->elements[0]->type;
|
||||
switch (type)
|
||||
{
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
/* Passed as separate arguments, but they wind up sequential. */
|
||||
break;
|
||||
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
/* Passed as separate arguments. Disjoint, but there's room
|
||||
enough in one slot to hold the pair. */
|
||||
size = ty->elements[0]->size;
|
||||
memcpy(valp + size, valp + 8, size);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
/* Passed as separate arguments. Disjoint, and each piece
|
||||
may need conversion back to float. */
|
||||
if (argn < 6)
|
||||
{
|
||||
valp = &argp[argn - 6];
|
||||
sts(valp, argp[argn - 6]);
|
||||
}
|
||||
if (argn + 1 < 6)
|
||||
sts(valp + 4, argp[argn + 1 - 6]);
|
||||
else
|
||||
*(UINT32 *)(valp + 4) = argp[argn + 1];
|
||||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
/* Passed as separate arguments. Only disjoint if one part
|
||||
is in fp regs and the other is on the stack. */
|
||||
if (argn < 5)
|
||||
valp = &argp[argn - 6];
|
||||
else if (argn == 5)
|
||||
{
|
||||
valp = alloca(16);
|
||||
((UINT64 *)valp)[0] = argp[5 - 6];
|
||||
((UINT64 *)valp)[1] = argp[6];
|
||||
}
|
||||
break;
|
||||
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
goto by_reference;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
argn += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
i++;
|
||||
avalue[i] = valp;
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
closure->fun (cif, rvalue, avalue, closure->user_data);
|
||||
fun (cif, rvalue, avalue, user_data);
|
||||
|
||||
/* Tell ffi_closure_osf how to perform return type promotions. */
|
||||
return cif->rtype->type;
|
||||
return (flags >> ALPHA_LD_SHIFT) & 0xff;
|
||||
}
|
||||
|
||||
@@ -44,9 +44,13 @@ typedef enum ffi_abi {
|
||||
} ffi_abi;
|
||||
#endif
|
||||
|
||||
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#define FFI_TRAMPOLINE_SIZE 24
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#define ALPHA_ST_VOID 0
|
||||
#define ALPHA_ST_INT 1
|
||||
#define ALPHA_ST_FLOAT 2
|
||||
#define ALPHA_ST_DOUBLE 3
|
||||
#define ALPHA_ST_CPLXF 4
|
||||
#define ALPHA_ST_CPLXD 5
|
||||
|
||||
#define ALPHA_LD_VOID 0
|
||||
#define ALPHA_LD_INT64 1
|
||||
#define ALPHA_LD_INT32 2
|
||||
#define ALPHA_LD_UINT16 3
|
||||
#define ALPHA_LD_SINT16 4
|
||||
#define ALPHA_LD_UINT8 5
|
||||
#define ALPHA_LD_SINT8 6
|
||||
#define ALPHA_LD_FLOAT 7
|
||||
#define ALPHA_LD_DOUBLE 8
|
||||
#define ALPHA_LD_CPLXF 9
|
||||
#define ALPHA_LD_CPLXD 10
|
||||
|
||||
#define ALPHA_ST_SHIFT 0
|
||||
#define ALPHA_LD_SHIFT 8
|
||||
#define ALPHA_RET_IN_MEM 0x10000
|
||||
#define ALPHA_FLAGS(S, L) (((L) << ALPHA_LD_SHIFT) | (S))
|
||||
+161
-266
@@ -1,7 +1,7 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011 Red Hat
|
||||
|
||||
Alpha/OSF Foreign Function Interface
|
||||
osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011, 2014 Red Hat
|
||||
|
||||
Alpha/OSF Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -24,40 +24,49 @@
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
#include "internal.h"
|
||||
|
||||
.arch ev6
|
||||
.text
|
||||
|
||||
/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
|
||||
void *raddr, void (*fnaddr)(void));
|
||||
/* Aid in building a direct addressed jump table, 4 insns per entry. */
|
||||
.macro E index
|
||||
.align 4
|
||||
.org 99b + \index * 16
|
||||
.endm
|
||||
|
||||
Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
|
||||
/* ffi_call_osf (void *stack, void *frame, unsigned flags,
|
||||
void *raddr, void (*fnaddr)(void), void *closure)
|
||||
|
||||
Bit o trickiness here -- FRAME is the base of the stack frame
|
||||
for this function. This has been allocated by ffi_call. We also
|
||||
deallocate some of the stack that has been alloca'd. */
|
||||
|
||||
.align 3
|
||||
.align 4
|
||||
.globl ffi_call_osf
|
||||
.ent ffi_call_osf
|
||||
FFI_HIDDEN(ffi_call_osf)
|
||||
|
||||
ffi_call_osf:
|
||||
.frame $15, 32, $26, 0
|
||||
.mask 0x4008000, -32
|
||||
$LFB1:
|
||||
addq $16,$17,$1
|
||||
cfi_startproc
|
||||
cfi_def_cfa($17, 32)
|
||||
mov $16, $30
|
||||
stq $26, 0($1)
|
||||
stq $15, 8($1)
|
||||
stq $18, 16($1)
|
||||
mov $1, $15
|
||||
$LCFI1:
|
||||
stq $26, 0($17)
|
||||
stq $15, 8($17)
|
||||
mov $17, $15
|
||||
.prologue 0
|
||||
cfi_def_cfa_register($15)
|
||||
cfi_rel_offset($26, 0)
|
||||
cfi_rel_offset($15, 8)
|
||||
|
||||
stq $19, 24($1)
|
||||
mov $20, $27
|
||||
stq $18, 16($17) # save flags into frame
|
||||
stq $19, 24($17) # save rvalue into frame
|
||||
mov $20, $27 # fn into place for call
|
||||
mov $21, $1 # closure into static chain
|
||||
|
||||
# Load up all of the (potential) argument registers.
|
||||
ldq $16, 0($30)
|
||||
@@ -77,310 +86,196 @@ $LCFI1:
|
||||
lda $30, 48($30)
|
||||
|
||||
jsr $26, ($27), 0
|
||||
ldgp $29, 0($26)
|
||||
|
||||
# If the return value pointer is NULL, assume no return value.
|
||||
ldq $19, 24($15)
|
||||
ldq $18, 16($15)
|
||||
0:
|
||||
ldah $29, 0($26) !gpdisp!1
|
||||
ldq $2, 24($15) # reload rvalue
|
||||
lda $29, 0($29) !gpdisp!1
|
||||
ldq $3, 16($15) # reload flags
|
||||
lda $1, 99f-0b($26)
|
||||
ldq $26, 0($15)
|
||||
$LCFI2:
|
||||
beq $19, $noretval
|
||||
|
||||
# Store the return value out in the proper type.
|
||||
cmpeq $18, FFI_TYPE_INT, $1
|
||||
bne $1, $retint
|
||||
cmpeq $18, FFI_TYPE_FLOAT, $2
|
||||
bne $2, $retfloat
|
||||
cmpeq $18, FFI_TYPE_DOUBLE, $3
|
||||
bne $3, $retdouble
|
||||
|
||||
.align 3
|
||||
$noretval:
|
||||
ldq $15, 8($15)
|
||||
ret
|
||||
cfi_restore($26)
|
||||
cfi_restore($15)
|
||||
cfi_def_cfa($sp, 0)
|
||||
cmoveq $2, ALPHA_ST_VOID, $3 # mash null rvalue to void
|
||||
addq $3, $3, $3
|
||||
s8addq $3, $1, $1 # 99f + stcode * 16
|
||||
jmp $31, ($1), $st_int
|
||||
|
||||
.align 4
|
||||
$retint:
|
||||
stq $0, 0($19)
|
||||
nop
|
||||
ldq $15, 8($15)
|
||||
99:
|
||||
E ALPHA_ST_VOID
|
||||
ret
|
||||
E ALPHA_ST_INT
|
||||
$st_int:
|
||||
stq $0, 0($2)
|
||||
ret
|
||||
E ALPHA_ST_FLOAT
|
||||
sts $f0, 0($2)
|
||||
ret
|
||||
E ALPHA_ST_DOUBLE
|
||||
stt $f0, 0($2)
|
||||
ret
|
||||
E ALPHA_ST_CPLXF
|
||||
sts $f0, 0($2)
|
||||
sts $f1, 4($2)
|
||||
ret
|
||||
E ALPHA_ST_CPLXD
|
||||
stt $f0, 0($2)
|
||||
stt $f1, 8($2)
|
||||
ret
|
||||
|
||||
.align 4
|
||||
$retfloat:
|
||||
sts $f0, 0($19)
|
||||
nop
|
||||
ldq $15, 8($15)
|
||||
ret
|
||||
|
||||
.align 4
|
||||
$retdouble:
|
||||
stt $f0, 0($19)
|
||||
nop
|
||||
ldq $15, 8($15)
|
||||
ret
|
||||
$LFE1:
|
||||
|
||||
cfi_endproc
|
||||
.end ffi_call_osf
|
||||
|
||||
/* ffi_closure_osf(...)
|
||||
|
||||
Receives the closure argument in $1. */
|
||||
|
||||
.align 3
|
||||
#define CLOSURE_FS (16*8)
|
||||
|
||||
.align 4
|
||||
.globl ffi_go_closure_osf
|
||||
.ent ffi_go_closure_osf
|
||||
FFI_HIDDEN(ffi_go_closure_osf)
|
||||
|
||||
ffi_go_closure_osf:
|
||||
cfi_startproc
|
||||
ldgp $29, 0($27)
|
||||
subq $30, CLOSURE_FS, $30
|
||||
cfi_adjust_cfa_offset(CLOSURE_FS)
|
||||
stq $26, 0($30)
|
||||
.prologue 1
|
||||
cfi_rel_offset($26, 0)
|
||||
|
||||
stq $16, 10*8($30)
|
||||
stq $17, 11*8($30)
|
||||
stq $18, 12*8($30)
|
||||
|
||||
ldq $16, 8($1) # load cif
|
||||
ldq $17, 16($1) # load fun
|
||||
mov $1, $18 # closure is user_data
|
||||
br $do_closure
|
||||
|
||||
cfi_endproc
|
||||
.end ffi_go_closure_osf
|
||||
|
||||
.align 4
|
||||
.globl ffi_closure_osf
|
||||
.ent ffi_closure_osf
|
||||
FFI_HIDDEN(ffi_closure_osf)
|
||||
|
||||
ffi_closure_osf:
|
||||
.frame $30, 16*8, $26, 0
|
||||
.mask 0x4000000, -16*8
|
||||
$LFB2:
|
||||
cfi_startproc
|
||||
ldgp $29, 0($27)
|
||||
subq $30, 16*8, $30
|
||||
$LCFI5:
|
||||
subq $30, CLOSURE_FS, $30
|
||||
cfi_adjust_cfa_offset(CLOSURE_FS)
|
||||
stq $26, 0($30)
|
||||
$LCFI6:
|
||||
.prologue 1
|
||||
cfi_rel_offset($26, 0)
|
||||
|
||||
# Store all of the potential argument registers in va_list format.
|
||||
stq $16, 10*8($30)
|
||||
stq $17, 11*8($30)
|
||||
stq $18, 12*8($30)
|
||||
|
||||
ldq $16, 24($1) # load cif
|
||||
ldq $17, 32($1) # load fun
|
||||
ldq $18, 40($1) # load user_data
|
||||
|
||||
$do_closure:
|
||||
stq $19, 13*8($30)
|
||||
stq $20, 14*8($30)
|
||||
stq $21, 15*8($30)
|
||||
stt $f16, 4*8($30)
|
||||
stt $f17, 5*8($30)
|
||||
stt $f18, 6*8($30)
|
||||
stt $f19, 7*8($30)
|
||||
stt $f20, 8*8($30)
|
||||
stt $f21, 9*8($30)
|
||||
stq $16, 10*8($30)
|
||||
stq $17, 11*8($30)
|
||||
stq $18, 12*8($30)
|
||||
stq $19, 13*8($30)
|
||||
stq $20, 14*8($30)
|
||||
stq $21, 15*8($30)
|
||||
|
||||
# Call ffi_closure_osf_inner to do the bulk of the work.
|
||||
mov $1, $16
|
||||
lda $17, 2*8($30)
|
||||
lda $18, 10*8($30)
|
||||
lda $19, 2*8($30)
|
||||
lda $20, 10*8($30)
|
||||
jsr $26, ffi_closure_osf_inner
|
||||
ldgp $29, 0($26)
|
||||
0:
|
||||
ldah $29, 0($26) !gpdisp!2
|
||||
lda $2, 99f-0b($26)
|
||||
s4addq $0, 0, $1 # ldcode * 4
|
||||
ldq $0, 16($30) # preload return value
|
||||
s4addq $1, $2, $1 # 99f + ldcode * 16
|
||||
lda $29, 0($29) !gpdisp!2
|
||||
ldq $26, 0($30)
|
||||
|
||||
# Load up the return value in the proper type.
|
||||
lda $1, $load_table
|
||||
s4addq $0, $1, $1
|
||||
ldl $1, 0($1)
|
||||
addq $1, $29, $1
|
||||
cfi_restore($26)
|
||||
jmp $31, ($1), $load_32
|
||||
|
||||
.align 4
|
||||
$load_none:
|
||||
addq $30, 16*8, $30
|
||||
.macro epilogue
|
||||
addq $30, CLOSURE_FS, $30
|
||||
cfi_adjust_cfa_offset(-CLOSURE_FS)
|
||||
ret
|
||||
.align 4
|
||||
cfi_adjust_cfa_offset(CLOSURE_FS)
|
||||
.endm
|
||||
|
||||
.align 4
|
||||
$load_float:
|
||||
lds $f0, 16($30)
|
||||
nop
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
99:
|
||||
E ALPHA_LD_VOID
|
||||
epilogue
|
||||
|
||||
.align 4
|
||||
$load_double:
|
||||
ldt $f0, 16($30)
|
||||
nop
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
E ALPHA_LD_INT64
|
||||
epilogue
|
||||
|
||||
.align 4
|
||||
$load_u8:
|
||||
#ifdef __alpha_bwx__
|
||||
ldbu $0, 16($30)
|
||||
nop
|
||||
#else
|
||||
ldq $0, 16($30)
|
||||
and $0, 255, $0
|
||||
#endif
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
E ALPHA_LD_INT32
|
||||
$load_32:
|
||||
sextl $0, $0
|
||||
epilogue
|
||||
|
||||
.align 4
|
||||
$load_s8:
|
||||
#ifdef __alpha_bwx__
|
||||
ldbu $0, 16($30)
|
||||
sextb $0, $0
|
||||
#else
|
||||
ldq $0, 16($30)
|
||||
sll $0, 56, $0
|
||||
sra $0, 56, $0
|
||||
#endif
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
|
||||
.align 4
|
||||
$load_u16:
|
||||
#ifdef __alpha_bwx__
|
||||
ldwu $0, 16($30)
|
||||
nop
|
||||
#else
|
||||
ldq $0, 16($30)
|
||||
E ALPHA_LD_UINT16
|
||||
zapnot $0, 3, $0
|
||||
#endif
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
epilogue
|
||||
|
||||
.align 4
|
||||
$load_s16:
|
||||
E ALPHA_LD_SINT16
|
||||
#ifdef __alpha_bwx__
|
||||
ldwu $0, 16($30)
|
||||
sextw $0, $0
|
||||
#else
|
||||
ldq $0, 16($30)
|
||||
sll $0, 48, $0
|
||||
sra $0, 48, $0
|
||||
#endif
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
epilogue
|
||||
|
||||
.align 4
|
||||
$load_32:
|
||||
ldl $0, 16($30)
|
||||
nop
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
E ALPHA_LD_UINT8
|
||||
and $0, 0xff, $0
|
||||
epilogue
|
||||
|
||||
.align 4
|
||||
$load_64:
|
||||
ldq $0, 16($30)
|
||||
nop
|
||||
addq $30, 16*8, $30
|
||||
ret
|
||||
$LFE2:
|
||||
|
||||
.end ffi_closure_osf
|
||||
|
||||
#ifdef __ELF__
|
||||
.section .rodata
|
||||
E ALPHA_LD_SINT8
|
||||
#ifdef __alpha_bwx__
|
||||
sextb $0, $0
|
||||
#else
|
||||
.rdata
|
||||
sll $0, 56, $0
|
||||
sra $0, 56, $0
|
||||
#endif
|
||||
$load_table:
|
||||
.gprel32 $load_none # FFI_TYPE_VOID
|
||||
.gprel32 $load_32 # FFI_TYPE_INT
|
||||
.gprel32 $load_float # FFI_TYPE_FLOAT
|
||||
.gprel32 $load_double # FFI_TYPE_DOUBLE
|
||||
.gprel32 $load_none # FFI_TYPE_LONGDOUBLE
|
||||
.gprel32 $load_u8 # FFI_TYPE_UINT8
|
||||
.gprel32 $load_s8 # FFI_TYPE_SINT8
|
||||
.gprel32 $load_u16 # FFI_TYPE_UINT16
|
||||
.gprel32 $load_s16 # FFI_TYPE_SINT16
|
||||
.gprel32 $load_32 # FFI_TYPE_UINT32
|
||||
.gprel32 $load_32 # FFI_TYPE_SINT32
|
||||
.gprel32 $load_64 # FFI_TYPE_UINT64
|
||||
.gprel32 $load_64 # FFI_TYPE_SINT64
|
||||
.gprel32 $load_none # FFI_TYPE_STRUCT
|
||||
.gprel32 $load_64 # FFI_TYPE_POINTER
|
||||
epilogue
|
||||
|
||||
/* Assert that the table above is in sync with ffi.h. */
|
||||
E ALPHA_LD_FLOAT
|
||||
lds $f0, 16($sp)
|
||||
epilogue
|
||||
|
||||
#if FFI_TYPE_FLOAT != 2 \
|
||||
|| FFI_TYPE_DOUBLE != 3 \
|
||||
|| 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 \
|
||||
|| FFI_TYPE_SINT64 != 12 \
|
||||
|| FFI_TYPE_STRUCT != 13 \
|
||||
|| FFI_TYPE_POINTER != 14 \
|
||||
|| FFI_TYPE_LAST != 14
|
||||
#error "osf.S out of sync with ffi.h"
|
||||
#endif
|
||||
E ALPHA_LD_DOUBLE
|
||||
ldt $f0, 16($sp)
|
||||
epilogue
|
||||
|
||||
#ifdef __ELF__
|
||||
# define UA_SI .4byte
|
||||
# define FDE_ENCODING 0x1b /* pcrel sdata4 */
|
||||
# define FDE_ENCODE(X) .4byte X-.
|
||||
# define FDE_ARANGE(X) .4byte X
|
||||
#elif defined __osf__
|
||||
# define UA_SI .align 0; .long
|
||||
# define FDE_ENCODING 0x50 /* aligned absolute */
|
||||
# define FDE_ENCODE(X) .align 3; .quad X
|
||||
# define FDE_ARANGE(X) .align 0; .quad X
|
||||
#endif
|
||||
E ALPHA_LD_CPLXF
|
||||
lds $f0, 16($sp)
|
||||
lds $f1, 20($sp)
|
||||
epilogue
|
||||
|
||||
#ifdef __ELF__
|
||||
.section .eh_frame,EH_FRAME_FLAGS,@progbits
|
||||
#elif defined __osf__
|
||||
.data
|
||||
.align 3
|
||||
.globl _GLOBAL__F_ffi_call_osf
|
||||
_GLOBAL__F_ffi_call_osf:
|
||||
#endif
|
||||
__FRAME_BEGIN__:
|
||||
UA_SI $LECIE1-$LSCIE1 # Length of Common Information Entry
|
||||
$LSCIE1:
|
||||
UA_SI 0x0 # CIE Identifier Tag
|
||||
.byte 0x1 # CIE Version
|
||||
.ascii "zR\0" # CIE Augmentation
|
||||
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
|
||||
.byte 0x78 # sleb128 -8; CIE Data Alignment Factor
|
||||
.byte 26 # CIE RA Column
|
||||
.byte 0x1 # uleb128 0x1; Augmentation size
|
||||
.byte FDE_ENCODING # FDE Encoding
|
||||
.byte 0xc # DW_CFA_def_cfa
|
||||
.byte 30 # uleb128 column 30
|
||||
.byte 0 # uleb128 offset 0
|
||||
.align 3
|
||||
$LECIE1:
|
||||
$LSFDE1:
|
||||
UA_SI $LEFDE1-$LASFDE1 # FDE Length
|
||||
$LASFDE1:
|
||||
UA_SI $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset
|
||||
FDE_ENCODE($LFB1) # FDE initial location
|
||||
FDE_ARANGE($LFE1-$LFB1) # FDE address range
|
||||
.byte 0x0 # uleb128 0x0; Augmentation size
|
||||
E ALPHA_LD_CPLXD
|
||||
ldt $f0, 16($sp)
|
||||
ldt $f1, 24($sp)
|
||||
epilogue
|
||||
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
UA_SI $LCFI1-$LFB1
|
||||
.byte 0x9a # DW_CFA_offset, column 26
|
||||
.byte 4 # uleb128 4*-8
|
||||
.byte 0x8f # DW_CFA_offset, column 15
|
||||
.byte 0x3 # uleb128 3*-8
|
||||
.byte 0xc # DW_CFA_def_cfa
|
||||
.byte 15 # uleb128 column 15
|
||||
.byte 32 # uleb128 offset 32
|
||||
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
UA_SI $LCFI2-$LCFI1
|
||||
.byte 0xda # DW_CFA_restore, column 26
|
||||
.align 3
|
||||
$LEFDE1:
|
||||
|
||||
$LSFDE3:
|
||||
UA_SI $LEFDE3-$LASFDE3 # FDE Length
|
||||
$LASFDE3:
|
||||
UA_SI $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset
|
||||
FDE_ENCODE($LFB2) # FDE initial location
|
||||
FDE_ARANGE($LFE2-$LFB2) # FDE address range
|
||||
.byte 0x0 # uleb128 0x0; Augmentation size
|
||||
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
UA_SI $LCFI5-$LFB2
|
||||
.byte 0xe # DW_CFA_def_cfa_offset
|
||||
.byte 0x80,0x1 # uleb128 128
|
||||
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
UA_SI $LCFI6-$LCFI5
|
||||
.byte 0x9a # DW_CFA_offset, column 26
|
||||
.byte 16 # uleb128 offset 16*-8
|
||||
.align 3
|
||||
$LEFDE3:
|
||||
#if defined __osf__
|
||||
.align 0
|
||||
.long 0 # End of Table
|
||||
#endif
|
||||
cfi_endproc
|
||||
.end ffi_closure_osf
|
||||
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
|
||||
+697
-585
File diff suppressed because it is too large
Load Diff
+4
-6
@@ -53,19 +53,17 @@ typedef enum ffi_abi {
|
||||
|
||||
#define FFI_EXTRA_CIF_FIELDS \
|
||||
int vfp_used; \
|
||||
short vfp_reg_free, vfp_nargs; \
|
||||
unsigned short vfp_reg_free, vfp_nargs; \
|
||||
signed char vfp_args[16] \
|
||||
|
||||
/* Internally used. */
|
||||
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
|
||||
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
|
||||
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC
|
||||
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_TRAMPOLINE_SIZE 20
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#define FFI_TRAMPOLINE_SIZE 12
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# gentramp.sh - Copyright (c) 2010, Plausible Labs Cooperative, Inc.
|
||||
#
|
||||
# ARM Trampoline Page Generator
|
||||
#
|
||||
# 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.
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
PROGNAME=$0
|
||||
|
||||
# Each trampoline is exactly 3 instructions, or 12 bytes. If any of these values change,
|
||||
# the entire arm trampoline implementation must be updated to match, too.
|
||||
|
||||
# Size of an individual trampoline, in bytes
|
||||
TRAMPOLINE_SIZE=12
|
||||
|
||||
# Page size, in bytes
|
||||
PAGE_SIZE=4096
|
||||
|
||||
# Compute the size of the reachable config page; The first 16 bytes of the config page
|
||||
# are unreachable due to our maximum pc-relative ldr offset.
|
||||
PAGE_AVAIL=`expr $PAGE_SIZE - 16`
|
||||
|
||||
# Compute the number of of available trampolines.
|
||||
TRAMPOLINE_COUNT=`expr $PAGE_AVAIL / $TRAMPOLINE_SIZE`
|
||||
|
||||
header () {
|
||||
echo "# GENERATED CODE - DO NOT EDIT"
|
||||
echo "# This file was generated by $PROGNAME"
|
||||
echo ""
|
||||
|
||||
# Write out the license header
|
||||
cat << EOF
|
||||
# Copyright (c) 2010, Plausible Labs Cooperative, Inc.
|
||||
#
|
||||
# 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.
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
EOF
|
||||
|
||||
# Write out the trampoline table, aligned to the page boundary
|
||||
echo ".text"
|
||||
echo ".align 12"
|
||||
echo ".globl _ffi_closure_trampoline_table_page"
|
||||
echo "_ffi_closure_trampoline_table_page:"
|
||||
}
|
||||
|
||||
|
||||
# WARNING - Don't modify the trampoline code size without also updating the relevant libffi code
|
||||
trampoline () {
|
||||
cat << END
|
||||
|
||||
// trampoline
|
||||
// Save to stack
|
||||
stmfd sp!, {r0-r3}
|
||||
|
||||
// Load the context argument from the config page.
|
||||
// This places the first usable config value at _ffi_closure_trampoline_table-4080
|
||||
// This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc.
|
||||
ldr r0, [pc, #-4092]
|
||||
|
||||
// Load the jump address from the config page.
|
||||
ldr pc, [pc, #-4092]
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
main () {
|
||||
# Write out the header
|
||||
header
|
||||
|
||||
# Write out the trampolines
|
||||
local i=0
|
||||
while [ $i -lt ${TRAMPOLINE_COUNT} ]; do
|
||||
trampoline
|
||||
local i=`expr $i + 1`
|
||||
done
|
||||
}
|
||||
|
||||
main
|
||||
@@ -0,0 +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
|
||||
+264
-420
@@ -1,8 +1,8 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
|
||||
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
|
||||
|
||||
ARM Foreign Function Interface
|
||||
|
||||
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
|
||||
@@ -28,463 +28,307 @@
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#ifdef HAVE_MACHINE_ASM_H
|
||||
#include <machine/asm.h>
|
||||
#else
|
||||
#ifdef __USER_LABEL_PREFIX__
|
||||
#define CONCAT1(a, b) CONCAT2(a, b)
|
||||
#define CONCAT2(a, b) a ## b
|
||||
#include <ffi_cfi.h>
|
||||
#include "internal.h"
|
||||
|
||||
/* Use the right prefix for global labels. */
|
||||
#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
|
||||
#else
|
||||
#define CNAME(x) x
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#define ENTRY(x) .globl _##x; _##x:
|
||||
#else
|
||||
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
|
||||
#endif /* __APPLE__ */
|
||||
#endif
|
||||
|
||||
#ifdef __ELF__
|
||||
#define LSYM(x) .x
|
||||
#else
|
||||
#define LSYM(x) x
|
||||
#endif
|
||||
|
||||
/* Use the SOFTFP return value ABI on Mac OS X, as per the iOS ABI
|
||||
Function Call Guide */
|
||||
#ifdef __APPLE__
|
||||
#define __SOFTFP__
|
||||
#endif
|
||||
|
||||
/* We need a better way of testing for this, but for now, this is all
|
||||
we can do. */
|
||||
@ This selects the minimum architecture level required.
|
||||
#define __ARM_ARCH__ 3
|
||||
|
||||
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||
# undef __ARM_ARCH__
|
||||
# define __ARM_ARCH__ 4
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|
||||
|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|
||||
|| defined(__ARM_ARCH_5TEJ__)
|
||||
# undef __ARM_ARCH__
|
||||
# define __ARM_ARCH__ 5
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||
/* 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__)
|
||||
# undef __ARM_ARCH__
|
||||
# define __ARM_ARCH__ 6
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|
||||
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|
||||
|| defined(__ARM_ARCH_7EM__)
|
||||
# undef __ARM_ARCH__
|
||||
# define __ARM_ARCH__ 7
|
||||
#endif
|
||||
|
||||
#if __ARM_ARCH__ >= 5
|
||||
# define call_reg(x) blx x
|
||||
#elif defined (__ARM_ARCH_4T__)
|
||||
# define call_reg(x) mov lr, pc ; bx x
|
||||
# if defined(__thumb__) || defined(__THUMB_INTERWORK__)
|
||||
# define __INTERWORKING__
|
||||
# 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
|
||||
#else
|
||||
# define call_reg(x) mov lr, pc ; mov pc, x
|
||||
#endif
|
||||
|
||||
/* Conditionally compile unwinder directives. */
|
||||
.macro UNWIND text:vararg
|
||||
#ifdef __ARM_EABI__
|
||||
#define UNWIND
|
||||
#else
|
||||
#define UNWIND @
|
||||
\text
|
||||
#endif
|
||||
|
||||
.syntax unified
|
||||
|
||||
#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
|
||||
#define ARM_FUNC_START(name) \
|
||||
.text; \
|
||||
.align 2; \
|
||||
.thumb; \
|
||||
.thumb_func; \
|
||||
ENTRY(name); \
|
||||
bx pc; \
|
||||
nop; \
|
||||
.arm; \
|
||||
UNWIND .fnstart; \
|
||||
_L__##name:
|
||||
#else
|
||||
#define ARM_FUNC_START(name) \
|
||||
.text; \
|
||||
.align 2; \
|
||||
.arm; \
|
||||
ENTRY(name); \
|
||||
UNWIND .fnstart
|
||||
.endm
|
||||
#if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
|
||||
.cfi_sections .debug_frame
|
||||
#endif
|
||||
|
||||
.macro RETLDM regs=, cond=, dirn=ia
|
||||
#if defined (__INTERWORKING__)
|
||||
.ifc "\regs",""
|
||||
ldr\cond lr, [sp], #4
|
||||
.else
|
||||
ldm\cond\dirn sp!, {\regs, lr}
|
||||
.endif
|
||||
bx\cond lr
|
||||
#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
|
||||
.ifc "\regs",""
|
||||
ldr\cond pc, [sp], #4
|
||||
.else
|
||||
ldm\cond\dirn sp!, {\regs, pc}
|
||||
.endif
|
||||
# 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(name, gl) \
|
||||
.align 3; \
|
||||
.ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \
|
||||
TYPE(name, %function); \
|
||||
CNAME(name):
|
||||
|
||||
#define ARM_FUNC_END(name) \
|
||||
SIZE(name)
|
||||
|
||||
/* Aid in defining a jump table with 8 bytes between entries. */
|
||||
.macro E index
|
||||
.if . - 0b - 8*\index
|
||||
.error "type table out of sync"
|
||||
.endif
|
||||
.endm
|
||||
|
||||
@ r0: ffi_prep_args
|
||||
@ r1: &ecif
|
||||
@ r2: cif->bytes
|
||||
@ r3: fig->flags
|
||||
@ sp+0: ecif.rvalue
|
||||
.text
|
||||
.syntax unified
|
||||
.arm
|
||||
|
||||
@ This assumes we are using gas.
|
||||
ARM_FUNC_START(ffi_call_SYSV)
|
||||
@ Save registers
|
||||
stmfd sp!, {r0-r3, fp, lr}
|
||||
UNWIND .save {r0-r3, fp, lr}
|
||||
mov fp, sp
|
||||
/* We require interworking on LDM, which implies ARMv5T,
|
||||
which implies the existance of BLX. */
|
||||
.arch armv5t
|
||||
|
||||
UNWIND .setfp fp, sp
|
||||
/* 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. */
|
||||
|
||||
@ Make room for all of the new args.
|
||||
sub sp, fp, r2
|
||||
@ r0: stack
|
||||
@ r1: frame
|
||||
@ r2: fn
|
||||
@ r3: vfp_used
|
||||
|
||||
@ Place all of the ffi_prep_args in position
|
||||
mov r0, sp
|
||||
@ r1 already set
|
||||
ARM_FUNC_START(ffi_call_VFP, 1)
|
||||
UNWIND .fnstart
|
||||
cfi_startproc
|
||||
|
||||
@ Call ffi_prep_args(stack, &ecif)
|
||||
bl CNAME(ffi_prep_args_SYSV)
|
||||
cmp r3, #3 @ load only d0 if possible
|
||||
ldcle p11, cr0, [r0] @ vldrle d0, [sp]
|
||||
ldcgt p11, cr0, [r0], {16} @ vldmgt sp, {d0-d7}
|
||||
add r0, r0, #64 @ discard the vfp register args
|
||||
/* FALLTHRU */
|
||||
ARM_FUNC_END(ffi_call_VFP)
|
||||
|
||||
@ move first 4 parameters in registers
|
||||
ldmia sp, {r0-r3}
|
||||
ARM_FUNC_START(ffi_call_SYSV, 1)
|
||||
stm r1, {fp, lr}
|
||||
mov fp, r1
|
||||
|
||||
@ and adjust stack
|
||||
sub lr, fp, sp @ cif->bytes == fp - sp
|
||||
ldr ip, [fp] @ load fn() in advance
|
||||
cmp lr, #16
|
||||
movhs lr, #16
|
||||
add sp, sp, lr
|
||||
@ 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)
|
||||
|
||||
@ call (fn) (...)
|
||||
call_reg(ip)
|
||||
|
||||
@ Remove the space we pushed for the args
|
||||
mov sp, fp
|
||||
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
|
||||
ldr r2, [sp, #24]
|
||||
@ Load r3 with the return type code
|
||||
ldr r2, [fp, #8]
|
||||
ldr r3, [fp, #12]
|
||||
|
||||
@ Load r3 with the return type code
|
||||
ldr r3, [sp, #12]
|
||||
@ Deallocate the stack with the arguments.
|
||||
mov sp, fp
|
||||
cfi_def_cfa_register(sp)
|
||||
|
||||
@ If the return value pointer is NULL, assume no return value.
|
||||
cmp r2, #0
|
||||
beq LSYM(Lepilogue)
|
||||
@ Store values stored in registers.
|
||||
.align 3
|
||||
add pc, pc, r3, lsl #3
|
||||
nop
|
||||
0:
|
||||
E ARM_TYPE_VFP_S
|
||||
stc p10, cr0, [r2] @ vstr s0, [r2]
|
||||
pop {fp,pc}
|
||||
E ARM_TYPE_VFP_D
|
||||
stc p11, cr0, [r2] @ vstr d0, [r2]
|
||||
pop {fp,pc}
|
||||
E ARM_TYPE_VFP_N
|
||||
stc p11, cr0, [r2], {8} @ vstm r2, {d0-d3}
|
||||
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}
|
||||
|
||||
@ return INT
|
||||
cmp r3, #FFI_TYPE_INT
|
||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
||||
cmpne r3, #FFI_TYPE_FLOAT
|
||||
#endif
|
||||
streq r0, [r2]
|
||||
beq LSYM(Lepilogue)
|
||||
|
||||
@ return INT64
|
||||
cmp r3, #FFI_TYPE_SINT64
|
||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
||||
cmpne r3, #FFI_TYPE_DOUBLE
|
||||
#endif
|
||||
stmiaeq r2, {r0, r1}
|
||||
|
||||
#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
|
||||
beq LSYM(Lepilogue)
|
||||
|
||||
@ return FLOAT
|
||||
cmp r3, #FFI_TYPE_FLOAT
|
||||
stfeqs f0, [r2]
|
||||
beq LSYM(Lepilogue)
|
||||
|
||||
@ return DOUBLE or LONGDOUBLE
|
||||
cmp r3, #FFI_TYPE_DOUBLE
|
||||
stfeqd f0, [r2]
|
||||
#endif
|
||||
|
||||
LSYM(Lepilogue):
|
||||
#if defined (__INTERWORKING__)
|
||||
ldmia sp!, {r0-r3,fp, lr}
|
||||
bx lr
|
||||
#else
|
||||
ldmia sp!, {r0-r3,fp, pc}
|
||||
#endif
|
||||
|
||||
.ffi_call_SYSV_end:
|
||||
UNWIND .fnend
|
||||
#ifdef __ELF__
|
||||
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
||||
#endif
|
||||
cfi_endproc
|
||||
UNWIND .fnend
|
||||
ARM_FUNC_END(ffi_call_SYSV)
|
||||
|
||||
|
||||
/*
|
||||
unsigned int FFI_HIDDEN
|
||||
ffi_closure_inner (closure, respp, args)
|
||||
ffi_closure *closure;
|
||||
void **respp;
|
||||
void *args;
|
||||
int ffi_closure_inner_* (cif, fun, user_data, frame)
|
||||
*/
|
||||
|
||||
ARM_FUNC_START(ffi_closure_SYSV)
|
||||
UNWIND .pad #16
|
||||
ARM_FUNC_START(ffi_go_closure_SYSV, 1)
|
||||
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, 1)
|
||||
UNWIND .fnstart
|
||||
cfi_startproc
|
||||
stmdb sp!, {r0-r3} @ save argument regs
|
||||
cfi_adjust_cfa_offset(16)
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+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, 1)
|
||||
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, 1)
|
||||
UNWIND .fnstart
|
||||
cfi_startproc
|
||||
stmdb sp!, {r0-r3} @ save argument regs
|
||||
cfi_adjust_cfa_offset(16)
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data
|
||||
0:
|
||||
add ip, sp, #16
|
||||
stmfd sp!, {ip, lr}
|
||||
UNWIND .save {r0, lr}
|
||||
add r2, sp, #8
|
||||
UNWIND .pad #16
|
||||
sub sp, sp, #16
|
||||
str sp, [sp, #8]
|
||||
add r1, sp, #8
|
||||
bl CNAME(ffi_closure_inner)
|
||||
cmp r0, #FFI_TYPE_INT
|
||||
beq .Lretint
|
||||
sub sp, sp, #64+32 @ allocate frame
|
||||
cfi_adjust_cfa_offset(64+32)
|
||||
stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7}
|
||||
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(ffi_closure_ret, 0)
|
||||
cfi_startproc
|
||||
cfi_rel_offset(sp, 0)
|
||||
cfi_rel_offset(lr, 4)
|
||||
0:
|
||||
E ARM_TYPE_VFP_S
|
||||
ldc p10, cr0, [r2] @ vldr s0, [r2]
|
||||
ldm sp, {sp,pc}
|
||||
E ARM_TYPE_VFP_D
|
||||
ldc p11, cr0, [r2] @ vldr d0, [r2]
|
||||
ldm sp, {sp,pc}
|
||||
E ARM_TYPE_VFP_N
|
||||
ldc p11, cr0, [r2], {8} @ vldm r2, {d0-d3}
|
||||
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
|
||||
|
||||
/* ??? The iOS support should be updated. The first insn used to
|
||||
be STMFD, but that's been moved into ffi_closure_SYSV. If the
|
||||
writable page is put after this one we can make use of the
|
||||
pc+8 feature of the architecture. We can also reduce the size
|
||||
of the thunk to 8 and pack more of these into the page.
|
||||
|
||||
In the meantime, simply replace the STMFD with a NOP so as to
|
||||
keep all the magic numbers the same within ffi.c. */
|
||||
|
||||
.align 12
|
||||
ARM_FUNC_START(ffi_closure_trampoline_table_page)
|
||||
.rept 4096 / 12
|
||||
nop
|
||||
ldr ip, [pc, #-4092]
|
||||
ldr pc, [pc, #-4092]
|
||||
.endr
|
||||
|
||||
cmp r0, #FFI_TYPE_FLOAT
|
||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
||||
beq .Lretint
|
||||
#else
|
||||
beq .Lretfloat
|
||||
#endif
|
||||
|
||||
cmp r0, #FFI_TYPE_DOUBLE
|
||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
||||
beq .Lretlonglong
|
||||
#else
|
||||
beq .Lretdouble
|
||||
#endif
|
||||
ARM_FUNC_START(ffi_arm_trampoline, 1)
|
||||
0: adr ip, 0b
|
||||
ldr pc, 1f
|
||||
1: .long 0
|
||||
ARM_FUNC_END(ffi_arm_trampoline)
|
||||
|
||||
cmp r0, #FFI_TYPE_LONGDOUBLE
|
||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
||||
beq .Lretlonglong
|
||||
#else
|
||||
beq .Lretlongdouble
|
||||
#endif
|
||||
|
||||
cmp r0, #FFI_TYPE_SINT64
|
||||
beq .Lretlonglong
|
||||
.Lclosure_epilogue:
|
||||
add sp, sp, #16
|
||||
ldmfd sp, {sp, pc}
|
||||
.Lretint:
|
||||
ldr r0, [sp]
|
||||
b .Lclosure_epilogue
|
||||
.Lretlonglong:
|
||||
ldr r0, [sp]
|
||||
ldr r1, [sp, #4]
|
||||
b .Lclosure_epilogue
|
||||
|
||||
#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
|
||||
.Lretfloat:
|
||||
ldfs f0, [sp]
|
||||
b .Lclosure_epilogue
|
||||
.Lretdouble:
|
||||
ldfd f0, [sp]
|
||||
b .Lclosure_epilogue
|
||||
.Lretlongdouble:
|
||||
ldfd f0, [sp]
|
||||
b .Lclosure_epilogue
|
||||
#endif
|
||||
|
||||
.ffi_closure_SYSV_end:
|
||||
UNWIND .fnend
|
||||
#ifdef __ELF__
|
||||
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
|
||||
#endif
|
||||
|
||||
|
||||
/* Below are VFP hard-float ABI call and closure implementations.
|
||||
Add VFP FPU directive here. This is only compiled into the library
|
||||
under EABI. */
|
||||
#ifdef __ARM_EABI__
|
||||
.fpu vfp
|
||||
|
||||
@ r0: fn
|
||||
@ r1: &ecif
|
||||
@ r2: cif->bytes
|
||||
@ r3: fig->flags
|
||||
@ sp+0: ecif.rvalue
|
||||
|
||||
ARM_FUNC_START(ffi_call_VFP)
|
||||
@ Save registers
|
||||
stmfd sp!, {r0-r3, fp, lr}
|
||||
UNWIND .save {r0-r3, fp, lr}
|
||||
mov fp, sp
|
||||
UNWIND .setfp fp, sp
|
||||
|
||||
@ Make room for all of the new args.
|
||||
sub sp, sp, r2
|
||||
|
||||
@ Make room for loading VFP args
|
||||
sub sp, sp, #64
|
||||
|
||||
@ Place all of the ffi_prep_args in position
|
||||
mov r0, sp
|
||||
@ r1 already set
|
||||
sub r2, fp, #64 @ VFP scratch space
|
||||
|
||||
@ Call ffi_prep_args(stack, &ecif, vfp_space)
|
||||
bl CNAME(ffi_prep_args_VFP)
|
||||
|
||||
@ Load VFP register args if needed
|
||||
cmp r0, #0
|
||||
mov ip, fp
|
||||
beq LSYM(Lbase_args)
|
||||
|
||||
@ Load only d0 if possible
|
||||
cmp r0, #3
|
||||
sub ip, fp, #64
|
||||
flddle d0, [ip]
|
||||
fldmiadgt ip, {d0-d7}
|
||||
|
||||
LSYM(Lbase_args):
|
||||
@ move first 4 parameters in registers
|
||||
ldmia sp, {r0-r3}
|
||||
|
||||
@ and adjust stack
|
||||
sub lr, ip, sp @ cif->bytes == (fp - 64) - sp
|
||||
ldr ip, [fp] @ load fn() in advance
|
||||
cmp lr, #16
|
||||
movhs lr, #16
|
||||
add sp, sp, lr
|
||||
|
||||
@ call (fn) (...)
|
||||
call_reg(ip)
|
||||
|
||||
@ Remove the space we pushed for the args
|
||||
mov sp, fp
|
||||
|
||||
@ Load r2 with the pointer to storage for
|
||||
@ the return value
|
||||
ldr r2, [sp, #24]
|
||||
|
||||
@ Load r3 with the return type code
|
||||
ldr r3, [sp, #12]
|
||||
|
||||
@ If the return value pointer is NULL,
|
||||
@ assume no return value.
|
||||
cmp r2, #0
|
||||
beq LSYM(Lepilogue_vfp)
|
||||
|
||||
cmp r3, #FFI_TYPE_INT
|
||||
streq r0, [r2]
|
||||
beq LSYM(Lepilogue_vfp)
|
||||
|
||||
cmp r3, #FFI_TYPE_SINT64
|
||||
stmeqia r2, {r0, r1}
|
||||
beq LSYM(Lepilogue_vfp)
|
||||
|
||||
cmp r3, #FFI_TYPE_FLOAT
|
||||
fstseq s0, [r2]
|
||||
beq LSYM(Lepilogue_vfp)
|
||||
|
||||
cmp r3, #FFI_TYPE_DOUBLE
|
||||
fstdeq d0, [r2]
|
||||
beq LSYM(Lepilogue_vfp)
|
||||
|
||||
cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT
|
||||
cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE
|
||||
fstmiadeq r2, {d0-d3}
|
||||
|
||||
LSYM(Lepilogue_vfp):
|
||||
RETLDM "r0-r3,fp"
|
||||
|
||||
.ffi_call_VFP_end:
|
||||
UNWIND .fnend
|
||||
.size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP)
|
||||
|
||||
|
||||
ARM_FUNC_START(ffi_closure_VFP)
|
||||
fstmfdd sp!, {d0-d7}
|
||||
@ r0-r3, then d0-d7
|
||||
UNWIND .pad #80
|
||||
add ip, sp, #80
|
||||
stmfd sp!, {ip, lr}
|
||||
UNWIND .save {r0, lr}
|
||||
add r2, sp, #72
|
||||
add r3, sp, #8
|
||||
UNWIND .pad #72
|
||||
sub sp, sp, #72
|
||||
str sp, [sp, #64]
|
||||
add r1, sp, #64
|
||||
bl CNAME(ffi_closure_inner)
|
||||
|
||||
cmp r0, #FFI_TYPE_INT
|
||||
beq .Lretint_vfp
|
||||
|
||||
cmp r0, #FFI_TYPE_FLOAT
|
||||
beq .Lretfloat_vfp
|
||||
|
||||
cmp r0, #FFI_TYPE_DOUBLE
|
||||
cmpne r0, #FFI_TYPE_LONGDOUBLE
|
||||
beq .Lretdouble_vfp
|
||||
|
||||
cmp r0, #FFI_TYPE_SINT64
|
||||
beq .Lretlonglong_vfp
|
||||
|
||||
cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT
|
||||
beq .Lretfloat_struct_vfp
|
||||
|
||||
cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE
|
||||
beq .Lretdouble_struct_vfp
|
||||
|
||||
.Lclosure_epilogue_vfp:
|
||||
add sp, sp, #72
|
||||
ldmfd sp, {sp, pc}
|
||||
|
||||
.Lretfloat_vfp:
|
||||
flds s0, [sp]
|
||||
b .Lclosure_epilogue_vfp
|
||||
.Lretdouble_vfp:
|
||||
fldd d0, [sp]
|
||||
b .Lclosure_epilogue_vfp
|
||||
.Lretint_vfp:
|
||||
ldr r0, [sp]
|
||||
b .Lclosure_epilogue_vfp
|
||||
.Lretlonglong_vfp:
|
||||
ldmia sp, {r0, r1}
|
||||
b .Lclosure_epilogue_vfp
|
||||
.Lretfloat_struct_vfp:
|
||||
fldmiad sp, {d0-d1}
|
||||
b .Lclosure_epilogue_vfp
|
||||
.Lretdouble_struct_vfp:
|
||||
fldmiad sp, {d0-d3}
|
||||
b .Lclosure_epilogue_vfp
|
||||
|
||||
.ffi_closure_VFP_end:
|
||||
UNWIND .fnend
|
||||
.size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP)
|
||||
#endif
|
||||
|
||||
ENTRY(ffi_arm_trampoline)
|
||||
stmfd sp!, {r0-r3}
|
||||
ldr r0, [pc]
|
||||
ldr pc, [pc]
|
||||
#endif /* FFI_EXEC_TRAMPOLINE_TABLE */
|
||||
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -147,9 +147,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
||||
#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||
/* Make space for the return structure pointer */
|
||||
if (cif->rtype->type == FFI_TYPE_STRUCT
|
||||
#ifdef SPARC
|
||||
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
|
||||
#endif
|
||||
#ifdef TILE
|
||||
&& (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
|
||||
#endif
|
||||
@@ -179,14 +176,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
||||
FFI_ASSERT_VALID_TYPE(*ptr);
|
||||
|
||||
#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||
#ifdef SPARC
|
||||
if (((*ptr)->type == FFI_TYPE_STRUCT
|
||||
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
|
||||
|| ((*ptr)->type == FFI_TYPE_LONGDOUBLE
|
||||
&& cif->abi != FFI_V9))
|
||||
bytes += sizeof(void*);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Add any padding if necessary */
|
||||
if (((*ptr)->alignment - 1) & bytes)
|
||||
|
||||
+342
-555
@@ -27,655 +27,442 @@
|
||||
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef SPARC64
|
||||
|
||||
/* ffi_prep_args is called by the assembly routine once stack space
|
||||
has been allocated for the function's arguments */
|
||||
|
||||
void ffi_prep_args_v8(char *stack, extended_cif *ecif)
|
||||
{
|
||||
int i;
|
||||
void **p_argv;
|
||||
char *argp;
|
||||
ffi_type **p_arg;
|
||||
|
||||
/* Skip 16 words for the window save area */
|
||||
argp = stack + 16*sizeof(int);
|
||||
|
||||
/* This should only really be done when we are returning a structure,
|
||||
however, it's faster just to do it all the time...
|
||||
|
||||
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
|
||||
*(int *) argp = (long)ecif->rvalue;
|
||||
|
||||
/* And 1 word for the structure return value. */
|
||||
argp += sizeof(int);
|
||||
|
||||
#ifdef USING_PURIFY
|
||||
/* Purify will probably complain in our assembly routine, unless we
|
||||
zero out this memory. */
|
||||
|
||||
((int*)argp)[0] = 0;
|
||||
((int*)argp)[1] = 0;
|
||||
((int*)argp)[2] = 0;
|
||||
((int*)argp)[3] = 0;
|
||||
((int*)argp)[4] = 0;
|
||||
((int*)argp)[5] = 0;
|
||||
#endif
|
||||
|
||||
p_argv = ecif->avalue;
|
||||
|
||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
|
||||
{
|
||||
size_t z;
|
||||
|
||||
if ((*p_arg)->type == FFI_TYPE_STRUCT
|
||||
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
||||
all further uses in this file will refer to the 128-bit type. */
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE
|
||||
# if FFI_TYPE_LONGDOUBLE != 4
|
||||
# error FFI_TYPE_LONGDOUBLE out of date
|
||||
# endif
|
||||
#else
|
||||
# undef FFI_TYPE_LONGDOUBLE
|
||||
# define FFI_TYPE_LONGDOUBLE 4
|
||||
#endif
|
||||
)
|
||||
{
|
||||
*(unsigned int *) argp = (unsigned long)(* p_argv);
|
||||
z = sizeof(int);
|
||||
}
|
||||
else
|
||||
{
|
||||
z = (*p_arg)->size;
|
||||
if (z < sizeof(int))
|
||||
{
|
||||
z = sizeof(int);
|
||||
switch ((*p_arg)->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
*(signed int *) argp = *(SINT8 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
*(unsigned int *) argp = *(UINT8 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
*(signed int *) argp = *(SINT16 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT16:
|
||||
*(unsigned int *) argp = *(UINT16 *)(* p_argv);
|
||||
break;
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(argp, *p_argv, z);
|
||||
}
|
||||
}
|
||||
p_argv++;
|
||||
argp += z;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int ffi_prep_args_v9(char *stack, extended_cif *ecif)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int tmp;
|
||||
void **p_argv;
|
||||
char *argp;
|
||||
ffi_type **p_arg;
|
||||
|
||||
tmp = 0;
|
||||
|
||||
/* Skip 16 words for the window save area */
|
||||
argp = stack + 16*sizeof(long long);
|
||||
|
||||
#ifdef USING_PURIFY
|
||||
/* Purify will probably complain in our assembly routine, unless we
|
||||
zero out this memory. */
|
||||
|
||||
((long long*)argp)[0] = 0;
|
||||
((long long*)argp)[1] = 0;
|
||||
((long long*)argp)[2] = 0;
|
||||
((long long*)argp)[3] = 0;
|
||||
((long long*)argp)[4] = 0;
|
||||
((long long*)argp)[5] = 0;
|
||||
#endif
|
||||
|
||||
p_argv = ecif->avalue;
|
||||
|
||||
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
|
||||
ecif->cif->rtype->size > 32)
|
||||
{
|
||||
*(unsigned long long *) argp = (unsigned long)ecif->rvalue;
|
||||
argp += sizeof(long long);
|
||||
tmp = 1;
|
||||
}
|
||||
|
||||
for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
|
||||
i++, p_arg++)
|
||||
{
|
||||
size_t z;
|
||||
|
||||
z = (*p_arg)->size;
|
||||
switch ((*p_arg)->type)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
if (z > 16)
|
||||
{
|
||||
/* For structures larger than 16 bytes we pass reference. */
|
||||
*(unsigned long long *) argp = (unsigned long)* p_argv;
|
||||
argp += sizeof(long long);
|
||||
tmp++;
|
||||
p_argv++;
|
||||
continue;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
#endif
|
||||
ret = 1; /* We should promote into FP regs as well as integer. */
|
||||
break;
|
||||
}
|
||||
if (z < sizeof(long long))
|
||||
{
|
||||
switch ((*p_arg)->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
*(signed long long *) argp = *(SINT8 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
*(unsigned long long *) argp = *(UINT8 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
*(signed long long *) argp = *(SINT16 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT16:
|
||||
*(unsigned long long *) argp = *(UINT16 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT32:
|
||||
*(signed long long *) argp = *(SINT32 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT32:
|
||||
*(unsigned long long *) argp = *(UINT32 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
*(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
memcpy(argp, *p_argv, z);
|
||||
break;
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
}
|
||||
z = sizeof(long long);
|
||||
tmp++;
|
||||
}
|
||||
else if (z == sizeof(long long))
|
||||
{
|
||||
memcpy(argp, *p_argv, z);
|
||||
z = sizeof(long long);
|
||||
tmp++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((tmp & 1) && (*p_arg)->alignment > 8)
|
||||
{
|
||||
tmp++;
|
||||
argp += sizeof(long long);
|
||||
}
|
||||
memcpy(argp, *p_argv, z);
|
||||
z = 2 * sizeof(long long);
|
||||
tmp += 2;
|
||||
}
|
||||
p_argv++;
|
||||
argp += z;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
int wordsize;
|
||||
|
||||
if (cif->abi != FFI_V9)
|
||||
{
|
||||
wordsize = 4;
|
||||
|
||||
/* If we are returning a struct, this will already have been added.
|
||||
Otherwise we need to add it because it's always got to be there! */
|
||||
|
||||
if (cif->rtype->type != FFI_TYPE_STRUCT)
|
||||
cif->bytes += wordsize;
|
||||
|
||||
/* sparc call frames require that space is allocated for 6 args,
|
||||
even if they aren't used. Make that space if necessary. */
|
||||
|
||||
if (cif->bytes < 4*6+4)
|
||||
cif->bytes = 4*6+4;
|
||||
}
|
||||
else
|
||||
{
|
||||
wordsize = 8;
|
||||
|
||||
/* sparc call frames require that space is allocated for 6 args,
|
||||
even if they aren't used. Make that space if necessary. */
|
||||
|
||||
if (cif->bytes < 8*6)
|
||||
cif->bytes = 8*6;
|
||||
}
|
||||
|
||||
/* Adjust cif->bytes. to include 16 words for the window save area,
|
||||
and maybe the struct/union return pointer area, */
|
||||
|
||||
cif->bytes += 16 * wordsize;
|
||||
|
||||
/* The stack must be 2 word aligned, so round bytes up
|
||||
appropriately. */
|
||||
|
||||
cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
|
||||
ffi_type *rtype = cif->rtype;
|
||||
int rtt = rtype->type;
|
||||
size_t bytes;
|
||||
int i, n, flags;
|
||||
|
||||
/* Set the return type flag */
|
||||
switch (cif->rtype->type)
|
||||
switch (rtt)
|
||||
{
|
||||
case FFI_TYPE_VOID:
|
||||
flags = SPARC_RET_VOID;
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = SPARC_RET_F_1;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
flags = SPARC_RET_F_2;
|
||||
break;
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
#endif
|
||||
cif->flags = cif->rtype->type;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
if (cif->abi == FFI_V9 && cif->rtype->size > 32)
|
||||
cif->flags = FFI_TYPE_VOID;
|
||||
else
|
||||
cif->flags = FFI_TYPE_STRUCT;
|
||||
flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
|
||||
flags |= SPARC_RET_STRUCT;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT8:
|
||||
flags = SPARC_RET_SINT8;
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
flags = SPARC_RET_UINT8;
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
flags = SPARC_RET_SINT16;
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
if (cif->abi == FFI_V9)
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
else
|
||||
cif->flags = cif->rtype->type;
|
||||
flags = SPARC_RET_UINT16;
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_POINTER:
|
||||
flags = SPARC_RET_UINT32;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
if (cif->abi == FFI_V9)
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
else
|
||||
cif->flags = FFI_TYPE_SINT64;
|
||||
flags = SPARC_RET_INT64;
|
||||
break;
|
||||
case FFI_TYPE_COMPLEX:
|
||||
rtt = rtype->elements[0]->type;
|
||||
switch (rtt)
|
||||
{
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = SPARC_RET_F_2;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
flags = SPARC_RET_F_4;
|
||||
break;
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
flags = SPARC_RET_F_8;
|
||||
break;
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
flags = SPARC_RET_INT128;
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
flags = SPARC_RET_INT64;
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT16:
|
||||
flags = SP_V8_RET_CPLX16;
|
||||
break;
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
flags = SP_V8_RET_CPLX8;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
cif->flags = flags;
|
||||
|
||||
bytes = 0;
|
||||
for (i = 0, n = cif->nargs; i < n; ++i)
|
||||
{
|
||||
ffi_type *ty = cif->arg_types[i];
|
||||
size_t z = ty->size;
|
||||
int tt = ty->type;
|
||||
|
||||
switch (tt)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
by_reference:
|
||||
/* Passed by reference. */
|
||||
z = 4;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
tt = ty->elements[0]->type;
|
||||
if (tt == FFI_TYPE_FLOAT || z > 8)
|
||||
goto by_reference;
|
||||
/* FALLTHRU */
|
||||
|
||||
default:
|
||||
z = ALIGN(z, 4);
|
||||
}
|
||||
bytes += z;
|
||||
}
|
||||
|
||||
/* Sparc call frames require that space is allocated for 6 args,
|
||||
even if they aren't used. Make that space if necessary. */
|
||||
if (bytes < 6 * 4)
|
||||
bytes = 6 * 4;
|
||||
|
||||
/* The ABI always requires space for the struct return pointer. */
|
||||
bytes += 4;
|
||||
|
||||
/* The stack must be 2 word aligned, so round bytes up appropriately. */
|
||||
bytes = ALIGN(bytes, 2 * 4);
|
||||
|
||||
/* Include the call frame to prep_args. */
|
||||
bytes += 4*16 + 4*8;
|
||||
cif->bytes = bytes;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
|
||||
extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
|
||||
|
||||
int FFI_HIDDEN
|
||||
ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
|
||||
{
|
||||
ffi_type **ptr = &arg->elements[0];
|
||||
ffi_type **p_arg;
|
||||
int flags = cif->flags;
|
||||
int i, nargs;
|
||||
|
||||
while (*ptr != NULL)
|
||||
if (rvalue == NULL)
|
||||
{
|
||||
if (off & ((*ptr)->alignment - 1))
|
||||
off = ALIGN(off, (*ptr)->alignment);
|
||||
|
||||
switch ((*ptr)->type)
|
||||
if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
|
||||
off = ALIGN(off, FFI_SIZEOF_ARG);
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
#endif
|
||||
memmove(ret + off, flt + off, (*ptr)->size);
|
||||
off += (*ptr)->size;
|
||||
break;
|
||||
default:
|
||||
memmove(ret + off, intg + off, (*ptr)->size);
|
||||
off += (*ptr)->size;
|
||||
break;
|
||||
/* Since we pass the pointer to the callee, we need a value.
|
||||
We allowed for this space in ffi_call, before ffi_call_v8
|
||||
alloca'd the space. */
|
||||
rvalue = (char *)argp + cif->bytes;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SPARC64
|
||||
extern int ffi_call_v9(void *, extended_cif *, unsigned,
|
||||
unsigned, unsigned *, void (*fn)(void));
|
||||
#else
|
||||
extern int ffi_call_v8(void *, extended_cif *, unsigned,
|
||||
unsigned, unsigned *, void (*fn)(void));
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
void ffi_flush_icache (void *, size_t);
|
||||
#endif
|
||||
|
||||
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
extended_cif ecif;
|
||||
void *rval = rvalue;
|
||||
|
||||
ecif.cif = cif;
|
||||
ecif.avalue = avalue;
|
||||
|
||||
/* If the return value is a struct and we don't have a return */
|
||||
/* value address then we need to make one */
|
||||
|
||||
ecif.rvalue = rvalue;
|
||||
if (cif->rtype->type == FFI_TYPE_STRUCT)
|
||||
{
|
||||
if (cif->rtype->size <= 32)
|
||||
rval = alloca(64);
|
||||
else
|
||||
{
|
||||
rval = NULL;
|
||||
if (rvalue == NULL)
|
||||
ecif.rvalue = alloca(cif->rtype->size);
|
||||
/* Otherwise, we can ignore the return value. */
|
||||
flags = SPARC_RET_VOID;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cif->abi)
|
||||
/* This could only really be done when we are returning a structure.
|
||||
However, the space is reserved so we can do it unconditionally. */
|
||||
*argp++ = (unsigned long)rvalue;
|
||||
|
||||
#ifdef USING_PURIFY
|
||||
/* Purify will probably complain in our assembly routine,
|
||||
unless we zero out this memory. */
|
||||
memset(argp, 0, 6*4);
|
||||
#endif
|
||||
|
||||
p_arg = cif->arg_types;
|
||||
for (i = 0, nargs = cif->nargs; i < nargs; i++)
|
||||
{
|
||||
case FFI_V8:
|
||||
#ifdef SPARC64
|
||||
/* We don't yet support calling 32bit code from 64bit */
|
||||
FFI_ASSERT(0);
|
||||
#else
|
||||
if (rvalue && (cif->rtype->type == FFI_TYPE_STRUCT
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
|| cif->flags == FFI_TYPE_LONGDOUBLE
|
||||
#endif
|
||||
))
|
||||
ffi_type *ty = p_arg[i];
|
||||
void *a = avalue[i];
|
||||
int tt = ty->type;
|
||||
size_t z;
|
||||
|
||||
switch (tt)
|
||||
{
|
||||
/* For v8, we need an "unimp" with size of returning struct */
|
||||
/* behind "call", so we alloc some executable space for it. */
|
||||
/* l7 is used, we need to make sure v8.S doesn't use %l7. */
|
||||
unsigned int *call_struct = NULL;
|
||||
ffi_closure_alloc(32, (void **)&call_struct);
|
||||
if (call_struct)
|
||||
case FFI_TYPE_STRUCT:
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
by_reference:
|
||||
*argp++ = (unsigned long)a;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
memcpy(argp, a, 8);
|
||||
argp += 2;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_POINTER:
|
||||
*argp++ = *(unsigned *)a;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
*argp++ = *(UINT8 *)a;
|
||||
break;
|
||||
case FFI_TYPE_SINT8:
|
||||
*argp++ = *(SINT8 *)a;
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
*argp++ = *(UINT16 *)a;
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
*argp++ = *(SINT16 *)a;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
tt = ty->elements[0]->type;
|
||||
z = ty->size;
|
||||
if (tt == FFI_TYPE_FLOAT || z > 8)
|
||||
goto by_reference;
|
||||
if (z < 4)
|
||||
{
|
||||
unsigned long f = (unsigned long)fn;
|
||||
call_struct[0] = 0xae10001f; /* mov %i7, %l7 */
|
||||
call_struct[1] = 0xbe10000f; /* mov %o7, %i7 */
|
||||
call_struct[2] = 0x03000000 | f >> 10; /* sethi %hi(fn), %g1 */
|
||||
call_struct[3] = 0x9fc06000 | (f & 0x3ff); /* jmp %g1+%lo(fn), %o7 */
|
||||
call_struct[4] = 0x01000000; /* nop */
|
||||
if (cif->rtype->size < 0x7f)
|
||||
call_struct[5] = cif->rtype->size; /* unimp */
|
||||
else
|
||||
call_struct[5] = 0x01000000; /* nop */
|
||||
call_struct[6] = 0x81c7e008; /* ret */
|
||||
call_struct[7] = 0xbe100017; /* mov %l7, %i7 */
|
||||
#ifdef __GNUC__
|
||||
asm volatile ("iflush %0; iflush %0+8; iflush %0+16; iflush %0+24" : :
|
||||
"r" (call_struct) : "memory");
|
||||
/* SPARC v8 requires 5 instructions for flush to be visible */
|
||||
asm volatile ("nop; nop; nop; nop; nop");
|
||||
#else
|
||||
ffi_flush_icache (call_struct, 32);
|
||||
#endif
|
||||
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
|
||||
cif->flags, rvalue, call_struct);
|
||||
ffi_closure_free(call_struct);
|
||||
memcpy((char *)argp + 4 - z, a, z);
|
||||
argp++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
|
||||
cif->flags, rvalue, fn);
|
||||
memcpy(argp, a, z);
|
||||
argp += z / 4;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
|
||||
cif->flags, rvalue, fn);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case FFI_V9:
|
||||
#ifdef SPARC64
|
||||
ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
|
||||
cif->flags, rval, fn);
|
||||
if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
|
||||
ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
|
||||
#else
|
||||
/* And vice versa */
|
||||
FFI_ASSERT(0);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
size_t bytes = cif->bytes;
|
||||
|
||||
#ifdef SPARC64
|
||||
extern void ffi_closure_v9(void);
|
||||
FFI_ASSERT (cif->abi == FFI_V8);
|
||||
|
||||
/* If we've not got a return value, we need to create one if we've
|
||||
got to pass the return value to the callee. Otherwise ignore it. */
|
||||
if (rvalue == NULL
|
||||
&& (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
|
||||
bytes += ALIGN (cif->rtype->size, 8);
|
||||
|
||||
ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
static inline void
|
||||
ffi_flush_icache (void *p)
|
||||
{
|
||||
/* SPARC v8 requires 5 instructions for flush to be visible */
|
||||
asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop"
|
||||
: : "r" (p) : "memory");
|
||||
}
|
||||
#else
|
||||
extern void ffi_closure_v8(void);
|
||||
extern void ffi_flush_icache (void *) FFI_HIDDEN;
|
||||
#endif
|
||||
|
||||
extern void ffi_closure_v8(void) FFI_HIDDEN;
|
||||
extern void ffi_go_closure_v8(void) FFI_HIDDEN;
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
ffi_prep_closure_loc (ffi_closure *closure,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
|
||||
unsigned long fn;
|
||||
#ifdef SPARC64
|
||||
/* Trampoline address is equal to the closure address. We take advantage
|
||||
of that to reduce the trampoline size by 8 bytes. */
|
||||
if (cif->abi != FFI_V9)
|
||||
return FFI_BAD_ABI;
|
||||
fn = (unsigned long) ffi_closure_v9;
|
||||
tramp[0] = 0x83414000; /* rd %pc, %g1 */
|
||||
tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
|
||||
tramp[2] = 0x81c14000; /* jmp %g5 */
|
||||
tramp[3] = 0x01000000; /* nop */
|
||||
*((unsigned long *) &tramp[4]) = fn;
|
||||
#else
|
||||
unsigned long ctx = (unsigned long) codeloc;
|
||||
unsigned long ctx = (unsigned long) closure;
|
||||
unsigned long fn = (unsigned long) ffi_closure_v8;
|
||||
|
||||
if (cif->abi != FFI_V8)
|
||||
return FFI_BAD_ABI;
|
||||
fn = (unsigned long) ffi_closure_v8;
|
||||
|
||||
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
|
||||
tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
|
||||
tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
|
||||
tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
|
||||
#endif
|
||||
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
closure->user_data = user_data;
|
||||
|
||||
/* Flush the Icache. closure is 8 bytes aligned. */
|
||||
#ifdef __GNUC__
|
||||
#ifdef SPARC64
|
||||
asm volatile ("flush %0; flush %0+8" : : "r" (closure) : "memory");
|
||||
#else
|
||||
asm volatile ("iflush %0; iflush %0+8" : : "r" (closure) : "memory");
|
||||
/* SPARC v8 requires 5 instructions for flush to be visible */
|
||||
asm volatile ("nop; nop; nop; nop; nop");
|
||||
#endif
|
||||
#else
|
||||
ffi_flush_icache (closure, 16);
|
||||
#endif
|
||||
ffi_flush_icache (closure);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
int
|
||||
ffi_closure_sparc_inner_v8(ffi_closure *closure,
|
||||
void *rvalue, unsigned long *gpr, unsigned long *scratch)
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*))
|
||||
{
|
||||
if (cif->abi != FFI_V8)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
closure->tramp = ffi_go_closure_v8;
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
int FFI_HIDDEN
|
||||
ffi_closure_sparc_inner_v8(ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data, void *rvalue,
|
||||
unsigned long *argp)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
ffi_type **arg_types;
|
||||
void **avalue;
|
||||
int i, argn;
|
||||
int i, nargs, flags;
|
||||
|
||||
cif = closure->cif;
|
||||
arg_types = cif->arg_types;
|
||||
avalue = alloca(cif->nargs * sizeof(void *));
|
||||
nargs = cif->nargs;
|
||||
flags = cif->flags;
|
||||
avalue = alloca(nargs * sizeof(void *));
|
||||
|
||||
/* Copy the caller's structure return address so that the closure
|
||||
returns the data directly to the caller. */
|
||||
if (cif->flags == FFI_TYPE_STRUCT
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
|| cif->flags == FFI_TYPE_LONGDOUBLE
|
||||
#endif
|
||||
)
|
||||
rvalue = (void *) gpr[0];
|
||||
returns the data directly to the caller. Also install it so we
|
||||
can return the address in %o0. */
|
||||
if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
|
||||
{
|
||||
void *new_rvalue = (void *)*argp;
|
||||
*(void **)rvalue = new_rvalue;
|
||||
rvalue = new_rvalue;
|
||||
}
|
||||
|
||||
/* Always skip the structure return address. */
|
||||
argn = 1;
|
||||
argp++;
|
||||
|
||||
/* Grab the addresses of the arguments from the stack frame. */
|
||||
for (i = 0; i < cif->nargs; i++)
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
if (arg_types[i]->type == FFI_TYPE_STRUCT
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE
|
||||
#endif
|
||||
)
|
||||
ffi_type *ty = arg_types[i];
|
||||
int tt = ty->type;
|
||||
void *a = argp;
|
||||
size_t z;
|
||||
|
||||
switch (tt)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
by_reference:
|
||||
/* Straight copy of invisible reference. */
|
||||
avalue[i] = (void *)gpr[argn++];
|
||||
}
|
||||
else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
|
||||
|| arg_types[i]->type == FFI_TYPE_SINT64
|
||||
|| arg_types[i]->type == FFI_TYPE_UINT64)
|
||||
/* gpr is 8-byte aligned. */
|
||||
&& (argn % 2) != 0)
|
||||
{
|
||||
/* Align on a 8-byte boundary. */
|
||||
scratch[0] = gpr[argn];
|
||||
scratch[1] = gpr[argn+1];
|
||||
avalue[i] = scratch;
|
||||
scratch -= 2;
|
||||
argn += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Always right-justify. */
|
||||
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
|
||||
a = (void *)*argp;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
if ((unsigned long)a & 7)
|
||||
{
|
||||
/* Align on a 8-byte boundary. */
|
||||
UINT64 *tmp = alloca(8);
|
||||
*tmp = ((UINT64)argp[0] << 32) | argp[1];
|
||||
a = tmp;
|
||||
}
|
||||
argp++;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_POINTER:
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT16:
|
||||
a += 2;
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT8:
|
||||
a += 3;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
tt = ty->elements[0]->type;
|
||||
z = ty->size;
|
||||
if (tt == FFI_TYPE_FLOAT || z > 8)
|
||||
goto by_reference;
|
||||
if (z < 4)
|
||||
a += 4 - z;
|
||||
else if (z > 4)
|
||||
argp++;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
argp++;
|
||||
avalue[i] = a;
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
(closure->fun) (cif, rvalue, avalue, closure->user_data);
|
||||
fun (cif, rvalue, avalue, user_data);
|
||||
|
||||
/* Tell ffi_closure_sparc how to perform return type promotions. */
|
||||
return cif->rtype->type;
|
||||
}
|
||||
|
||||
int
|
||||
ffi_closure_sparc_inner_v9(ffi_closure *closure,
|
||||
void *rvalue, unsigned long *gpr, double *fpr)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
ffi_type **arg_types;
|
||||
void **avalue;
|
||||
int i, argn, fp_slot_max;
|
||||
|
||||
cif = closure->cif;
|
||||
arg_types = cif->arg_types;
|
||||
avalue = alloca(cif->nargs * sizeof(void *));
|
||||
|
||||
/* Copy the caller's structure return address so that the closure
|
||||
returns the data directly to the caller. */
|
||||
if (cif->flags == FFI_TYPE_VOID
|
||||
&& cif->rtype->type == FFI_TYPE_STRUCT)
|
||||
{
|
||||
rvalue = (void *) gpr[0];
|
||||
/* Skip the structure return address. */
|
||||
argn = 1;
|
||||
}
|
||||
else
|
||||
argn = 0;
|
||||
|
||||
fp_slot_max = 16 - argn;
|
||||
|
||||
/* Grab the addresses of the arguments from the stack frame. */
|
||||
for (i = 0; i < cif->nargs; i++)
|
||||
{
|
||||
if (arg_types[i]->type == FFI_TYPE_STRUCT)
|
||||
{
|
||||
if (arg_types[i]->size > 16)
|
||||
{
|
||||
/* Straight copy of invisible reference. */
|
||||
avalue[i] = (void *)gpr[argn++];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Left-justify. */
|
||||
ffi_v9_layout_struct(arg_types[i],
|
||||
0,
|
||||
(char *) &gpr[argn],
|
||||
(char *) &gpr[argn],
|
||||
(char *) &fpr[argn]);
|
||||
avalue[i] = &gpr[argn];
|
||||
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Right-justify. */
|
||||
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
|
||||
/* Align on a 16-byte boundary. */
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0)
|
||||
argn++;
|
||||
#endif
|
||||
if (i < fp_slot_max
|
||||
&& (arg_types[i]->type == FFI_TYPE_FLOAT
|
||||
|| arg_types[i]->type == FFI_TYPE_DOUBLE
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE
|
||||
#endif
|
||||
))
|
||||
avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
|
||||
else
|
||||
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
(closure->fun) (cif, rvalue, avalue, closure->user_data);
|
||||
|
||||
/* Tell ffi_closure_sparc how to perform return type promotions. */
|
||||
return cif->rtype->type;
|
||||
return flags;
|
||||
}
|
||||
#endif /* !SPARC64 */
|
||||
|
||||
@@ -0,0 +1,592 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 2011, 2013 Anthony Green
|
||||
Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
|
||||
|
||||
SPARC 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>
|
||||
#include <stdlib.h>
|
||||
#include "internal.h"
|
||||
|
||||
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
||||
all further uses in this file will refer to the 128-bit type. */
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
# if FFI_TYPE_LONGDOUBLE != 4
|
||||
# error FFI_TYPE_LONGDOUBLE out of date
|
||||
# endif
|
||||
#else
|
||||
# undef FFI_TYPE_LONGDOUBLE
|
||||
# define FFI_TYPE_LONGDOUBLE 4
|
||||
#endif
|
||||
|
||||
#ifdef SPARC64
|
||||
|
||||
/* Flatten the contents of a structure to the parts that are passed in
|
||||
floating point registers. The return is a bit mask wherein bit N
|
||||
set means bytes [4*n, 4*n+3] are passed in %fN.
|
||||
|
||||
We encode both the (running) size (maximum 32) and mask (maxumum 255)
|
||||
into one integer. The size is placed in the low byte, so that align
|
||||
and addition work correctly. The mask is placed in the second byte. */
|
||||
|
||||
static int
|
||||
ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
|
||||
{
|
||||
ffi_type **elts;
|
||||
ffi_type *t;
|
||||
|
||||
if (outer_type->type == FFI_TYPE_COMPLEX)
|
||||
{
|
||||
int m = 0, tt = outer_type->elements[0]->type;
|
||||
size_t z = outer_type->size;
|
||||
|
||||
if (tt == FFI_TYPE_FLOAT
|
||||
|| tt == FFI_TYPE_DOUBLE
|
||||
|| tt == FFI_TYPE_LONGDOUBLE)
|
||||
m = (1 << (z / 4)) - 1;
|
||||
return (m << 8) | z;
|
||||
}
|
||||
FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
|
||||
|
||||
for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
|
||||
{
|
||||
size_t z = t->size;
|
||||
int o, m, tt;
|
||||
|
||||
size_mask = ALIGN(size_mask, t->alignment);
|
||||
switch (t->type)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
size_mask = ffi_struct_float_mask (t, size_mask);
|
||||
continue;
|
||||
case FFI_TYPE_COMPLEX:
|
||||
tt = t->elements[0]->type;
|
||||
if (tt != FFI_TYPE_FLOAT
|
||||
&& tt != FFI_TYPE_DOUBLE
|
||||
&& tt != FFI_TYPE_LONGDOUBLE)
|
||||
break;
|
||||
/* FALLTHRU */
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
m = (1 << (z / 4)) - 1; /* compute mask for type */
|
||||
o = (size_mask >> 2) & 0x3f; /* extract word offset */
|
||||
size_mask |= m << (o + 8); /* insert mask into place */
|
||||
break;
|
||||
}
|
||||
size_mask += z;
|
||||
}
|
||||
|
||||
size_mask = ALIGN(size_mask, outer_type->alignment);
|
||||
FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
|
||||
|
||||
return size_mask;
|
||||
}
|
||||
|
||||
/* Merge floating point data into integer data. If the structure is
|
||||
entirely floating point, simply return a pointer to the fp data. */
|
||||
|
||||
static void *
|
||||
ffi_struct_float_merge (int size_mask, void *vi, void *vf)
|
||||
{
|
||||
int size = size_mask & 0xff;
|
||||
int mask = size_mask >> 8;
|
||||
int n = size >> 2;
|
||||
|
||||
if (mask == 0)
|
||||
return vi;
|
||||
else if (mask == (1 << n) - 1)
|
||||
return vf;
|
||||
else
|
||||
{
|
||||
unsigned int *wi = vi, *wf = vf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
if ((mask >> i) & 1)
|
||||
wi[i] = wf[i];
|
||||
|
||||
return vi;
|
||||
}
|
||||
}
|
||||
|
||||
/* Similar, but place the data into VD in the end. */
|
||||
|
||||
void FFI_HIDDEN
|
||||
ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf)
|
||||
{
|
||||
int size = size_mask & 0xff;
|
||||
int mask = size_mask >> 8;
|
||||
int n = size >> 2;
|
||||
|
||||
if (mask == 0)
|
||||
;
|
||||
else if (mask == (1 << n) - 1)
|
||||
vi = vf;
|
||||
else
|
||||
{
|
||||
unsigned int *wd = vd, *wi = vi, *wf = vf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
wd[i] = ((mask >> i) & 1 ? wf : wi)[i];
|
||||
return;
|
||||
}
|
||||
memcpy (vd, vi, size);
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
ffi_type *rtype = cif->rtype;
|
||||
int rtt = rtype->type;
|
||||
size_t bytes = 0;
|
||||
int i, n, flags;
|
||||
|
||||
/* Set the return type flag */
|
||||
switch (rtt)
|
||||
{
|
||||
case FFI_TYPE_VOID:
|
||||
flags = SPARC_RET_VOID;
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = SPARC_RET_F_1;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
flags = SPARC_RET_F_2;
|
||||
break;
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
flags = SPARC_RET_F_4;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
case FFI_TYPE_STRUCT:
|
||||
if (rtype->size > 32)
|
||||
{
|
||||
flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM;
|
||||
bytes = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
int size_mask = ffi_struct_float_mask (rtype, 0);
|
||||
int word_size = (size_mask >> 2) & 0x3f;
|
||||
int all_mask = (1 << word_size) - 1;
|
||||
int fp_mask = size_mask >> 8;
|
||||
|
||||
flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT;
|
||||
|
||||
/* For special cases of all-int or all-fp, we can return
|
||||
the value directly without popping through a struct copy. */
|
||||
if (fp_mask == 0)
|
||||
{
|
||||
if (rtype->alignment >= 8)
|
||||
{
|
||||
if (rtype->size == 8)
|
||||
flags = SPARC_RET_INT64;
|
||||
else if (rtype->size == 16)
|
||||
flags = SPARC_RET_INT128;
|
||||
}
|
||||
}
|
||||
else if (fp_mask == all_mask)
|
||||
switch (word_size)
|
||||
{
|
||||
case 1: flags = SPARC_RET_F_1; break;
|
||||
case 2: flags = SPARC_RET_F_2; break;
|
||||
case 3: flags = SP_V9_RET_F_3; break;
|
||||
case 4: flags = SPARC_RET_F_4; break;
|
||||
/* 5 word structures skipped; handled via RET_STRUCT. */
|
||||
case 6: flags = SPARC_RET_F_6; break;
|
||||
/* 7 word structures skipped; handled via RET_STRUCT. */
|
||||
case 8: flags = SPARC_RET_F_8; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT8:
|
||||
flags = SPARC_RET_SINT8;
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
flags = SPARC_RET_UINT8;
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
flags = SPARC_RET_SINT16;
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
flags = SPARC_RET_UINT16;
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
flags = SP_V9_RET_SINT32;
|
||||
break;
|
||||
case FFI_TYPE_UINT32:
|
||||
flags = SPARC_RET_UINT32;
|
||||
break;
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
flags = SPARC_RET_INT64;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
bytes = 0;
|
||||
for (i = 0, n = cif->nargs; i < n; ++i)
|
||||
{
|
||||
ffi_type *ty = cif->arg_types[i];
|
||||
size_t z = ty->size;
|
||||
size_t a = ty->alignment;
|
||||
|
||||
switch (ty->type)
|
||||
{
|
||||
case FFI_TYPE_COMPLEX:
|
||||
case FFI_TYPE_STRUCT:
|
||||
/* Large structs passed by reference. */
|
||||
if (z > 16)
|
||||
{
|
||||
a = z = 8;
|
||||
break;
|
||||
}
|
||||
/* Small structs may be passed in integer or fp regs or both. */
|
||||
if (bytes >= 16*8)
|
||||
break;
|
||||
if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
|
||||
break;
|
||||
/* FALLTHRU */
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
flags |= SPARC_FLAG_FP_ARGS;
|
||||
break;
|
||||
}
|
||||
bytes = ALIGN(bytes, a);
|
||||
bytes += ALIGN(z, 8);
|
||||
}
|
||||
|
||||
/* Sparc call frames require that space is allocated for 6 args,
|
||||
even if they aren't used. Make that space if necessary. */
|
||||
if (bytes < 6 * 8)
|
||||
bytes = 6 * 8;
|
||||
|
||||
/* The stack must be 2 word aligned, so round bytes up appropriately. */
|
||||
bytes = ALIGN(bytes, 16);
|
||||
|
||||
/* Include the call frame to prep_args. */
|
||||
bytes += 8*16 + 8*8;
|
||||
|
||||
cif->bytes = bytes;
|
||||
cif->flags = flags;
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
|
||||
|
||||
/* ffi_prep_args is called by the assembly routine once stack space
|
||||
has been allocated for the function's arguments */
|
||||
|
||||
int FFI_HIDDEN
|
||||
ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
|
||||
{
|
||||
ffi_type **p_arg;
|
||||
int flags = cif->flags;
|
||||
int i, nargs;
|
||||
|
||||
if (rvalue == NULL)
|
||||
{
|
||||
if (flags & SPARC_FLAG_RET_IN_MEM)
|
||||
{
|
||||
/* Since we pass the pointer to the callee, we need a value.
|
||||
We allowed for this space in ffi_call, before ffi_call_v8
|
||||
alloca'd the space. */
|
||||
rvalue = (char *)argp + cif->bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, we can ignore the return value. */
|
||||
flags = SPARC_RET_VOID;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USING_PURIFY
|
||||
/* Purify will probably complain in our assembly routine,
|
||||
unless we zero out this memory. */
|
||||
memset(argp, 0, 6*8);
|
||||
#endif
|
||||
|
||||
if (flags & SPARC_FLAG_RET_IN_MEM)
|
||||
*argp++ = (unsigned long)rvalue;
|
||||
|
||||
p_arg = cif->arg_types;
|
||||
for (i = 0, nargs = cif->nargs; i < nargs; i++)
|
||||
{
|
||||
ffi_type *ty = p_arg[i];
|
||||
void *a = avalue[i];
|
||||
size_t z;
|
||||
|
||||
switch (ty->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
*argp++ = *(SINT8 *)a;
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
*argp++ = *(UINT8 *)a;
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
*argp++ = *(SINT16 *)a;
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
*argp++ = *(UINT16 *)a;
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
*argp++ = *(SINT32 *)a;
|
||||
break;
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_FLOAT:
|
||||
*argp++ = *(UINT32 *)a;
|
||||
break;
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
*argp++ = *(UINT64 *)a;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
case FFI_TYPE_COMPLEX:
|
||||
case FFI_TYPE_STRUCT:
|
||||
z = ty->size;
|
||||
if (z > 16)
|
||||
{
|
||||
/* For structures larger than 16 bytes we pass reference. */
|
||||
*argp++ = (unsigned long)a;
|
||||
break;
|
||||
}
|
||||
if (((unsigned long)argp & 15) && ty->alignment > 8)
|
||||
argp++;
|
||||
memcpy(argp, a, z);
|
||||
argp += ALIGN(z, 8) / 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
size_t bytes = cif->bytes;
|
||||
|
||||
FFI_ASSERT (cif->abi == FFI_V9);
|
||||
|
||||
if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
|
||||
bytes += ALIGN (cif->rtype->size, 16);
|
||||
|
||||
ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
static inline void
|
||||
ffi_flush_icache (void *p)
|
||||
{
|
||||
asm volatile ("flush %0; flush %0+8" : : "r" (p) : "memory");
|
||||
}
|
||||
#else
|
||||
extern void ffi_flush_icache (void *) FFI_HIDDEN;
|
||||
#endif
|
||||
|
||||
extern void ffi_closure_v9(void) FFI_HIDDEN;
|
||||
extern void ffi_go_closure_v9(void) FFI_HIDDEN;
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
|
||||
unsigned long fn;
|
||||
|
||||
if (cif->abi != FFI_V9)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
/* Trampoline address is equal to the closure address. We take advantage
|
||||
of that to reduce the trampoline size by 8 bytes. */
|
||||
fn = (unsigned long) ffi_closure_v9;
|
||||
tramp[0] = 0x83414000; /* rd %pc, %g1 */
|
||||
tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
|
||||
tramp[2] = 0x81c14000; /* jmp %g5 */
|
||||
tramp[3] = 0x01000000; /* nop */
|
||||
*((unsigned long *) &tramp[4]) = fn;
|
||||
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
closure->user_data = user_data;
|
||||
|
||||
ffi_flush_icache (closure);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*))
|
||||
{
|
||||
if (cif->abi != FFI_V9)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
closure->tramp = ffi_go_closure_v9;
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
int FFI_HIDDEN
|
||||
ffi_closure_sparc_inner_v9(ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data, void *rvalue,
|
||||
unsigned long *gpr, unsigned long *fpr)
|
||||
{
|
||||
ffi_type **arg_types;
|
||||
void **avalue;
|
||||
int i, argn, argx, nargs, flags;
|
||||
|
||||
arg_types = cif->arg_types;
|
||||
nargs = cif->nargs;
|
||||
flags = cif->flags;
|
||||
|
||||
avalue = alloca(nargs * sizeof(void *));
|
||||
|
||||
/* Copy the caller's structure return address so that the closure
|
||||
returns the data directly to the caller. */
|
||||
if (flags & SPARC_FLAG_RET_IN_MEM)
|
||||
{
|
||||
rvalue = (void *) gpr[0];
|
||||
/* Skip the structure return address. */
|
||||
argn = 1;
|
||||
}
|
||||
else
|
||||
argn = 0;
|
||||
|
||||
/* Grab the addresses of the arguments from the stack frame. */
|
||||
for (i = 0; i < nargs; i++, argn = argx)
|
||||
{
|
||||
ffi_type *ty = arg_types[i];
|
||||
void *a = &gpr[argn];
|
||||
size_t z;
|
||||
|
||||
argx = argn + 1;
|
||||
switch (ty->type)
|
||||
{
|
||||
case FFI_TYPE_COMPLEX:
|
||||
case FFI_TYPE_STRUCT:
|
||||
z = ty->size;
|
||||
if (z > 16)
|
||||
a = *(void **)a;
|
||||
else
|
||||
{
|
||||
argx = argn + ALIGN (z, 8) / 8;
|
||||
if (argn < 16)
|
||||
{
|
||||
int size_mask = ffi_struct_float_mask (ty, 0);
|
||||
int argn_mask = (0xffff00 >> argn) & 0xff00;
|
||||
|
||||
/* Eliminate fp registers off the end. */
|
||||
size_mask = (size_mask & 0xff) | (size_mask & argn_mask);
|
||||
a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
argn = ALIGN (argn, 2);
|
||||
a = (argn < 16 ? fpr : gpr) + argn;
|
||||
argx = argn + 2;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
if (argn <= 16)
|
||||
a = fpr + argn;
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
if (argn <= 16)
|
||||
a = fpr + argn;
|
||||
a += 4;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
a += 4;
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT16:
|
||||
a += 6;
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT8:
|
||||
a += 7;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
avalue[i] = a;
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
fun (cif, rvalue, avalue, user_data);
|
||||
|
||||
/* Tell ffi_closure_sparc how to perform return type promotions. */
|
||||
return flags;
|
||||
}
|
||||
#endif /* SPARC64 */
|
||||
@@ -46,21 +46,24 @@ typedef signed long ffi_sarg;
|
||||
|
||||
typedef enum ffi_abi {
|
||||
FFI_FIRST_ABI = 0,
|
||||
FFI_V8,
|
||||
FFI_V8PLUS,
|
||||
FFI_V9,
|
||||
FFI_LAST_ABI,
|
||||
#ifdef SPARC64
|
||||
FFI_DEFAULT_ABI = FFI_V9
|
||||
FFI_V9,
|
||||
FFI_DEFAULT_ABI = FFI_V9,
|
||||
#else
|
||||
FFI_DEFAULT_ABI = FFI_V8
|
||||
FFI_V8,
|
||||
FFI_DEFAULT_ABI = FFI_V8,
|
||||
#endif
|
||||
FFI_LAST_ABI
|
||||
} ffi_abi;
|
||||
#endif
|
||||
|
||||
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
#ifdef SPARC64
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#define SPARC_RET_VOID 0
|
||||
#define SPARC_RET_STRUCT 1
|
||||
#define SPARC_RET_UINT8 2
|
||||
#define SPARC_RET_SINT8 3
|
||||
#define SPARC_RET_UINT16 4
|
||||
#define SPARC_RET_SINT16 5
|
||||
#define SPARC_RET_UINT32 6
|
||||
#define SP_V9_RET_SINT32 7 /* v9 only */
|
||||
#define SP_V8_RET_CPLX16 7 /* v8 only */
|
||||
#define SPARC_RET_INT64 8
|
||||
#define SPARC_RET_INT128 9
|
||||
|
||||
/* Note that F_7 is missing, and is handled by SPARC_RET_STRUCT. */
|
||||
#define SPARC_RET_F_8 10
|
||||
#define SPARC_RET_F_6 11
|
||||
#define SPARC_RET_F_4 12
|
||||
#define SPARC_RET_F_2 13
|
||||
#define SP_V9_RET_F_3 14 /* v9 only */
|
||||
#define SP_V8_RET_CPLX8 14 /* v8 only */
|
||||
#define SPARC_RET_F_1 15
|
||||
|
||||
#define SPARC_FLAG_RET_MASK 15
|
||||
#define SPARC_FLAG_RET_IN_MEM 32
|
||||
#define SPARC_FLAG_FP_ARGS 64
|
||||
|
||||
#define SPARC_SIZEMASK_SHIFT 8
|
||||
+281
-266
@@ -1,8 +1,8 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
v8.S - Copyright (c) 2013 The Written Word, Inc.
|
||||
Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc.
|
||||
|
||||
SPARC Foreign Function Interface
|
||||
|
||||
SPARC Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -25,179 +25,243 @@
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define STACKFRAME 96 /* Minimum stack framesize for SPARC */
|
||||
#define ARGS (64+4) /* Offset of register area in frame */
|
||||
#ifndef SPARC64
|
||||
|
||||
#ifndef __GNUC__
|
||||
.text
|
||||
.align 8
|
||||
.globl ffi_flush_icache
|
||||
.globl _ffi_flush_icache
|
||||
#define C2(X, Y) X ## Y
|
||||
#define C1(X, Y) C2(X, Y)
|
||||
|
||||
ffi_flush_icache:
|
||||
_ffi_flush_icache:
|
||||
add %o0, %o1, %o2
|
||||
#ifdef SPARC64
|
||||
1: flush %o0
|
||||
#else
|
||||
1: iflush %o0
|
||||
#ifdef __USER_LABEL_PREFIX__
|
||||
# define C(Y) C1(__USER_LABEL_PREFIX__, Y)
|
||||
#else
|
||||
# define C(Y) Y
|
||||
#endif
|
||||
add %o0, 8, %o0
|
||||
cmp %o0, %o2
|
||||
blt 1b
|
||||
#define L(Y) C1(.L, Y)
|
||||
|
||||
.text
|
||||
|
||||
#ifndef __GNUC__
|
||||
.align 8
|
||||
.globl C(ffi_flush_icache)
|
||||
.type C(ffi_flush_icache),@function
|
||||
FFI_HIDDEN(C(ffi_flush_icache))
|
||||
|
||||
C(ffi_flush_icache):
|
||||
cfi_startproc
|
||||
1: iflush %o0
|
||||
iflush %o+8
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
.ffi_flush_icache_end:
|
||||
.size ffi_flush_icache,.ffi_flush_icache_end-ffi_flush_icache
|
||||
nop
|
||||
cfi_endproc
|
||||
.size C(ffi_flush_icache), . - C(ffi_flush_icache)
|
||||
#endif
|
||||
|
||||
.text
|
||||
.macro E index
|
||||
.align 16
|
||||
.org 2b + \index * 16
|
||||
.endm
|
||||
|
||||
.align 8
|
||||
.globl ffi_call_v8
|
||||
.globl _ffi_call_v8
|
||||
|
||||
ffi_call_v8:
|
||||
_ffi_call_v8:
|
||||
.LLFB1:
|
||||
save %sp, -STACKFRAME, %sp
|
||||
.LLCFI0:
|
||||
|
||||
sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
|
||||
add %sp, STACKFRAME, %l0 ! %l0 has start of
|
||||
! frame to set up
|
||||
.globl C(ffi_call_v8)
|
||||
.type C(ffi_call_v8),@function
|
||||
FFI_HIDDEN(C(ffi_call_v8))
|
||||
|
||||
mov %l0, %o0 ! call routine to set up frame
|
||||
call %i0
|
||||
mov %i1, %o1 ! (delay)
|
||||
C(ffi_call_v8):
|
||||
cfi_startproc
|
||||
! Allocate a stack frame sized by ffi_call.
|
||||
save %sp, %o4, %sp
|
||||
cfi_def_cfa_register(%fp)
|
||||
cfi_window_save
|
||||
|
||||
ld [%l0+ARGS], %o0 ! call foreign function
|
||||
ld [%l0+ARGS+4], %o1
|
||||
ld [%l0+ARGS+8], %o2
|
||||
ld [%l0+ARGS+12], %o3
|
||||
ld [%l0+ARGS+16], %o4
|
||||
ld [%l0+ARGS+20], %o5
|
||||
call %i5
|
||||
mov %l0, %sp ! (delay) switch to frame
|
||||
nop ! STRUCT returning functions skip 12 instead of 8 bytes
|
||||
mov %i0, %o0 ! copy cif
|
||||
add %sp, 64+32, %o1 ! load args area
|
||||
mov %i2, %o2 ! copy rvalue
|
||||
call C(ffi_prep_args_v8)
|
||||
mov %i3, %o3 ! copy avalue
|
||||
|
||||
! If the return value pointer is NULL, assume no return value.
|
||||
tst %i4
|
||||
bz done
|
||||
add %sp, 32, %sp ! deallocate prep frame
|
||||
and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type
|
||||
srl %o0, SPARC_SIZEMASK_SHIFT, %l1 ! save return size
|
||||
ld [%sp+64+4], %o0 ! load all argument registers
|
||||
ld [%sp+64+8], %o1
|
||||
ld [%sp+64+12], %o2
|
||||
ld [%sp+64+16], %o3
|
||||
cmp %l0, SPARC_RET_STRUCT ! struct return needs an unimp 4
|
||||
ld [%sp+64+20], %o4
|
||||
be 8f
|
||||
ld [%sp+64+24], %o5
|
||||
|
||||
! Call foreign function
|
||||
call %i1
|
||||
mov %i5, %g2 ! load static chain
|
||||
|
||||
0: call 1f ! load pc in %o7
|
||||
sll %l0, 4, %l0
|
||||
1: add %o7, %l0, %o7 ! o7 = 0b + ret_type*16
|
||||
jmp %o7+(2f-0b)
|
||||
nop
|
||||
|
||||
! Note that each entry is 4 insns, enforced by the E macro.
|
||||
.align 16
|
||||
2:
|
||||
E SPARC_RET_VOID
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_STRUCT
|
||||
unimp
|
||||
E SPARC_RET_UINT8
|
||||
and %o0, 0xff, %o0
|
||||
st %o0, [%i2]
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_SINT8
|
||||
sll %o0, 24, %o0
|
||||
b 7f
|
||||
sra %o0, 24, %o0
|
||||
E SPARC_RET_UINT16
|
||||
sll %o0, 16, %o0
|
||||
b 7f
|
||||
srl %o0, 16, %o0
|
||||
E SPARC_RET_SINT16
|
||||
sll %o0, 16, %o0
|
||||
b 7f
|
||||
sra %o0, 16, %o0
|
||||
E SPARC_RET_UINT32
|
||||
7: st %o0, [%i2]
|
||||
ret
|
||||
restore
|
||||
E SP_V8_RET_CPLX16
|
||||
sth %o0, [%i2+2]
|
||||
b 9f
|
||||
srl %o0, 16, %o0
|
||||
E SPARC_RET_INT64
|
||||
st %o0, [%i2]
|
||||
st %o1, [%i2+4]
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_INT128
|
||||
std %o0, [%i2]
|
||||
std %o2, [%i2+8]
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_F_8
|
||||
st %f7, [%i2+7*4]
|
||||
nop
|
||||
|
||||
cmp %i3, FFI_TYPE_INT
|
||||
be,a done
|
||||
st %o0, [%i4] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_FLOAT
|
||||
be,a done
|
||||
st %f0, [%i4+0] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_DOUBLE
|
||||
be,a double
|
||||
st %f0, [%i4+0] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_SINT8
|
||||
be,a sint8
|
||||
sll %o0, 24, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_UINT8
|
||||
be,a uint8
|
||||
sll %o0, 24, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_SINT16
|
||||
be,a sint16
|
||||
sll %o0, 16, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_UINT16
|
||||
be,a uint16
|
||||
sll %o0, 16, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_SINT64
|
||||
be,a longlong
|
||||
st %o0, [%i4+0] ! (delay)
|
||||
done:
|
||||
st %f6, [%i2+6*4]
|
||||
nop
|
||||
E SPARC_RET_F_6
|
||||
st %f5, [%i2+5*4]
|
||||
nop
|
||||
st %f4, [%i2+4*4]
|
||||
nop
|
||||
E SPARC_RET_F_4
|
||||
st %f3, [%i2+3*4]
|
||||
nop
|
||||
st %f2, [%i2+2*4]
|
||||
nop
|
||||
E SPARC_RET_F_2
|
||||
st %f1, [%i2+4]
|
||||
st %f0, [%i2]
|
||||
ret
|
||||
restore
|
||||
|
||||
double:
|
||||
st %f1, [%i4+4]
|
||||
restore
|
||||
E SP_V8_RET_CPLX8
|
||||
stb %o0, [%i2+1]
|
||||
b 10f
|
||||
srl %o0, 8, %o0
|
||||
E SPARC_RET_F_1
|
||||
st %f0, [%i2]
|
||||
ret
|
||||
restore
|
||||
restore
|
||||
|
||||
sint8:
|
||||
sra %o0, 24, %o0
|
||||
st %o0, [%i4+0]
|
||||
.align 8
|
||||
9: sth %o0, [%i2]
|
||||
ret
|
||||
restore
|
||||
|
||||
uint8:
|
||||
srl %o0, 24, %o0
|
||||
st %o0, [%i4+0]
|
||||
restore
|
||||
.align 8
|
||||
10: stb %o0, [%i2]
|
||||
ret
|
||||
restore
|
||||
restore
|
||||
|
||||
sint16:
|
||||
sra %o0, 16, %o0
|
||||
st %o0, [%i4+0]
|
||||
! Struct returning functions expect and skip the unimp here.
|
||||
! To make it worse, conforming callees examine the unimp and
|
||||
! make sure the low 12 bits of the unimp match the size of
|
||||
! the struct being returned.
|
||||
.align 8
|
||||
8: call 1f ! load pc in %o7
|
||||
sll %l1, 2, %l0 ! size * 4
|
||||
1: sll %l1, 4, %l1 ! size * 16
|
||||
add %l0, %l1, %l0 ! size * 20
|
||||
add %o7, %l0, %o7 ! o7 = 0b + size*20
|
||||
jmp %o7+(2f-8b)
|
||||
mov %i5, %g2 ! load static chain
|
||||
2:
|
||||
.rept 0x1000
|
||||
call %i1
|
||||
nop
|
||||
unimp (. - 2b) / 20
|
||||
ret
|
||||
restore
|
||||
restore
|
||||
.endr
|
||||
|
||||
uint16:
|
||||
srl %o0, 16, %o0
|
||||
st %o0, [%i4+0]
|
||||
ret
|
||||
restore
|
||||
|
||||
longlong:
|
||||
st %o1, [%i4+4]
|
||||
ret
|
||||
restore
|
||||
.LLFE1:
|
||||
|
||||
.ffi_call_v8_end:
|
||||
.size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8
|
||||
cfi_endproc
|
||||
.size C(ffi_call_v8),. - C(ffi_call_v8)
|
||||
|
||||
|
||||
#undef STACKFRAME
|
||||
#define STACKFRAME 104 /* 16*4 register window +
|
||||
1*4 struct return +
|
||||
6*4 args backing store +
|
||||
3*4 locals */
|
||||
/* 16*4 register window + 1*4 struct return + 6*4 args backing store
|
||||
+ 8*4 return storage + 1*4 alignment. */
|
||||
#define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4)
|
||||
|
||||
/* ffi_closure_v8(...)
|
||||
|
||||
Receives the closure argument in %g2. */
|
||||
|
||||
.text
|
||||
.align 8
|
||||
.globl ffi_closure_v8
|
||||
|
||||
ffi_closure_v8:
|
||||
#ifdef HAVE_AS_REGISTER_PSEUDO_OP
|
||||
.register %g2, #scratch
|
||||
.register %g2, #scratch
|
||||
#endif
|
||||
.LLFB2:
|
||||
! Reserve frame space for all arguments in case
|
||||
! we need to align them on a 8-byte boundary.
|
||||
ld [%g2+FFI_TRAMPOLINE_SIZE], %g1
|
||||
ld [%g1+4], %g1
|
||||
sll %g1, 3, %g1
|
||||
add %g1, STACKFRAME, %g1
|
||||
! %g1 == STACKFRAME + 8*nargs
|
||||
neg %g1
|
||||
save %sp, %g1, %sp
|
||||
.LLCFI1:
|
||||
|
||||
.align 8
|
||||
.globl C(ffi_go_closure_v8)
|
||||
.type C(ffi_go_closure_v8),@function
|
||||
FFI_HIDDEN(C(ffi_go_closure_v8))
|
||||
|
||||
C(ffi_go_closure_v8):
|
||||
cfi_startproc
|
||||
save %sp, -STACKFRAME, %sp
|
||||
cfi_def_cfa_register(%fp)
|
||||
cfi_window_save
|
||||
|
||||
ld [%g2+4], %o0 ! load cif
|
||||
ld [%g2+8], %o1 ! load fun
|
||||
b 0f
|
||||
mov %g2, %o2 ! load user_data
|
||||
cfi_endproc
|
||||
.size C(ffi_go_closure_v8), . - C(ffi_go_closure_v8)
|
||||
|
||||
.align 8
|
||||
.globl C(ffi_closure_v8)
|
||||
.type C(ffi_closure_v8),@function
|
||||
FFI_HIDDEN(C(ffi_closure_v8))
|
||||
|
||||
C(ffi_closure_v8):
|
||||
cfi_startproc
|
||||
save %sp, -STACKFRAME, %sp
|
||||
cfi_def_cfa_register(%fp)
|
||||
cfi_window_save
|
||||
|
||||
ld [%g2+FFI_TRAMPOLINE_SIZE], %o0 ! load cif
|
||||
ld [%g2+FFI_TRAMPOLINE_SIZE+4], %o1 ! load fun
|
||||
ld [%g2+FFI_TRAMPOLINE_SIZE+8], %o2 ! load user_data
|
||||
0:
|
||||
! Store all of the potential argument registers in va_list format.
|
||||
st %i0, [%fp+68+0]
|
||||
st %i1, [%fp+68+4]
|
||||
@@ -207,140 +271,91 @@ ffi_closure_v8:
|
||||
st %i5, [%fp+68+20]
|
||||
|
||||
! Call ffi_closure_sparc_inner to do the bulk of the work.
|
||||
mov %g2, %o0
|
||||
add %fp, -8, %o1
|
||||
add %fp, 64, %o2
|
||||
add %fp, -8*4, %o3
|
||||
call ffi_closure_sparc_inner_v8
|
||||
add %fp, -16, %o3
|
||||
add %fp, 64, %o4
|
||||
|
||||
! Load up the return value in the proper type.
|
||||
! See ffi_prep_cif_machdep for the list of cases.
|
||||
cmp %o0, FFI_TYPE_VOID
|
||||
be done1
|
||||
|
||||
cmp %o0, FFI_TYPE_INT
|
||||
be done1
|
||||
ld [%fp-8], %i0
|
||||
|
||||
cmp %o0, FFI_TYPE_FLOAT
|
||||
be,a done1
|
||||
ld [%fp-8], %f0
|
||||
|
||||
cmp %o0, FFI_TYPE_DOUBLE
|
||||
be,a done1
|
||||
ldd [%fp-8], %f0
|
||||
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
cmp %o0, FFI_TYPE_LONGDOUBLE
|
||||
be done2
|
||||
#endif
|
||||
|
||||
cmp %o0, FFI_TYPE_STRUCT
|
||||
be done2
|
||||
|
||||
cmp %o0, FFI_TYPE_SINT64
|
||||
be,a done1
|
||||
ldd [%fp-8], %i0
|
||||
|
||||
cmp %o0, FFI_TYPE_UINT64
|
||||
be,a done1
|
||||
ldd [%fp-8], %i0
|
||||
|
||||
ld [%fp-8], %i0
|
||||
done1:
|
||||
jmp %i7+8
|
||||
0: call 1f
|
||||
and %o0, SPARC_FLAG_RET_MASK, %o0
|
||||
1: sll %o0, 4, %o0 ! o0 = o0 * 16
|
||||
add %o7, %o0, %o7 ! o7 = 0b + o0*16
|
||||
jmp %o7+(2f-0b)
|
||||
add %fp, -8*4, %i2
|
||||
|
||||
! Note that each entry is 4 insns, enforced by the E macro.
|
||||
.align 16
|
||||
2:
|
||||
E SPARC_RET_VOID
|
||||
ret
|
||||
restore
|
||||
done2:
|
||||
! Skip 'unimp'.
|
||||
E SPARC_RET_STRUCT
|
||||
ld [%i2], %i0
|
||||
jmp %i7+12
|
||||
restore
|
||||
.LLFE2:
|
||||
|
||||
.ffi_closure_v8_end:
|
||||
.size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8
|
||||
|
||||
#ifdef SPARC64
|
||||
#define WS 8
|
||||
#define nword xword
|
||||
#define uanword uaxword
|
||||
#else
|
||||
#define WS 4
|
||||
#define nword long
|
||||
#define uanword uaword
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RO_EH_FRAME
|
||||
.section ".eh_frame",#alloc
|
||||
#else
|
||||
.section ".eh_frame",#alloc,#write
|
||||
#endif
|
||||
.LLframe1:
|
||||
.uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
|
||||
.LLSCIE1:
|
||||
.uaword 0x0 ! CIE Identifier Tag
|
||||
.byte 0x1 ! CIE Version
|
||||
.ascii "zR\0" ! CIE Augmentation
|
||||
.byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
|
||||
.byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor
|
||||
.byte 0xf ! CIE RA Column
|
||||
.byte 0x1 ! uleb128 0x1; Augmentation size
|
||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
||||
.byte 0x1b ! FDE Encoding (pcrel sdata4)
|
||||
#else
|
||||
.byte 0x50 ! FDE Encoding (aligned absolute)
|
||||
#endif
|
||||
.byte 0xc ! DW_CFA_def_cfa
|
||||
.byte 0xe ! uleb128 0xe
|
||||
.byte 0x0 ! uleb128 0x0
|
||||
.align WS
|
||||
.LLECIE1:
|
||||
.LLSFDE1:
|
||||
.uaword .LLEFDE1-.LLASFDE1 ! FDE Length
|
||||
.LLASFDE1:
|
||||
.uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
|
||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
||||
.uaword %r_disp32(.LLFB1)
|
||||
.uaword .LLFE1-.LLFB1 ! FDE address range
|
||||
#else
|
||||
.align WS
|
||||
.nword .LLFB1
|
||||
.uanword .LLFE1-.LLFB1 ! FDE address range
|
||||
#endif
|
||||
.byte 0x0 ! uleb128 0x0; Augmentation size
|
||||
.byte 0x4 ! DW_CFA_advance_loc4
|
||||
.uaword .LLCFI0-.LLFB1
|
||||
.byte 0xd ! DW_CFA_def_cfa_register
|
||||
.byte 0x1e ! uleb128 0x1e
|
||||
.byte 0x2d ! DW_CFA_GNU_window_save
|
||||
.byte 0x9 ! DW_CFA_register
|
||||
.byte 0xf ! uleb128 0xf
|
||||
.byte 0x1f ! uleb128 0x1f
|
||||
.align WS
|
||||
.LLEFDE1:
|
||||
.LLSFDE2:
|
||||
.uaword .LLEFDE2-.LLASFDE2 ! FDE Length
|
||||
.LLASFDE2:
|
||||
.uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
|
||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
||||
.uaword %r_disp32(.LLFB2)
|
||||
.uaword .LLFE2-.LLFB2 ! FDE address range
|
||||
#else
|
||||
.align WS
|
||||
.nword .LLFB2
|
||||
.uanword .LLFE2-.LLFB2 ! FDE address range
|
||||
#endif
|
||||
.byte 0x0 ! uleb128 0x0; Augmentation size
|
||||
.byte 0x4 ! DW_CFA_advance_loc4
|
||||
.uaword .LLCFI1-.LLFB2
|
||||
.byte 0xd ! DW_CFA_def_cfa_register
|
||||
.byte 0x1e ! uleb128 0x1e
|
||||
.byte 0x2d ! DW_CFA_GNU_window_save
|
||||
.byte 0x9 ! DW_CFA_register
|
||||
.byte 0xf ! uleb128 0xf
|
||||
.byte 0x1f ! uleb128 0x1f
|
||||
.align WS
|
||||
.LLEFDE2:
|
||||
E SPARC_RET_UINT8
|
||||
ldub [%i2+3], %i0
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_SINT8
|
||||
ldsb [%i2+3], %i0
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_UINT16
|
||||
lduh [%i2+2], %i0
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_SINT16
|
||||
ldsh [%i2+2], %i0
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_UINT32
|
||||
ld [%i2], %i0
|
||||
ret
|
||||
restore
|
||||
E SP_V8_RET_CPLX16
|
||||
ld [%i2], %i0
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_INT64
|
||||
ldd [%i2], %i0
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_INT128
|
||||
ldd [%i2], %i0
|
||||
ldd [%i2+8], %i2
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_F_8
|
||||
ld [%i2+7*4], %f7
|
||||
nop
|
||||
ld [%i2+6*4], %f6
|
||||
nop
|
||||
E SPARC_RET_F_6
|
||||
ld [%i2+5*4], %f5
|
||||
nop
|
||||
ld [%i2+4*4], %f4
|
||||
nop
|
||||
E SPARC_RET_F_4
|
||||
ld [%i2+3*4], %f3
|
||||
nop
|
||||
ld [%i2+2*4], %f2
|
||||
nop
|
||||
E SPARC_RET_F_2
|
||||
ldd [%i2], %f0
|
||||
ret
|
||||
restore
|
||||
E SP_V8_RET_CPLX8
|
||||
lduh [%i2], %i0
|
||||
ret
|
||||
restore
|
||||
E SPARC_RET_F_1
|
||||
ld [%i2], %f0
|
||||
ret
|
||||
restore
|
||||
|
||||
cfi_endproc
|
||||
.size C(ffi_closure_v8), . - C(ffi_closure_v8)
|
||||
#endif /* !SPARC64 */
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
|
||||
+279
-209
@@ -27,105 +27,178 @@
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
#include "internal.h"
|
||||
|
||||
#ifdef SPARC64
|
||||
/* Only compile this in for 64bit builds, because otherwise the object file
|
||||
will have inproper architecture due to used instructions. */
|
||||
|
||||
#define STACKFRAME 176 /* Minimum stack framesize for SPARC 64-bit */
|
||||
#define C2(X, Y) X ## Y
|
||||
#define C1(X, Y) C2(X, Y)
|
||||
|
||||
#ifdef __USER_LABEL_PREFIX__
|
||||
# define C(Y) C1(__USER_LABEL_PREFIX__, Y)
|
||||
#else
|
||||
# define C(Y) Y
|
||||
#endif
|
||||
#define L(Y) C1(.L, Y)
|
||||
|
||||
.macro E index
|
||||
.align 16
|
||||
.org 2b + \index * 16
|
||||
.endm
|
||||
|
||||
#define STACK_BIAS 2047
|
||||
#define ARGS (128) /* Offset of register area in frame */
|
||||
|
||||
.text
|
||||
.text
|
||||
.align 8
|
||||
.globl ffi_call_v9
|
||||
.globl _ffi_call_v9
|
||||
.globl C(ffi_call_v9)
|
||||
.type C(ffi_call_v9),@function
|
||||
FFI_HIDDEN(C(ffi_call_v9))
|
||||
|
||||
ffi_call_v9:
|
||||
_ffi_call_v9:
|
||||
.LLFB1:
|
||||
save %sp, -STACKFRAME, %sp
|
||||
.LLCFI0:
|
||||
C(ffi_call_v9):
|
||||
cfi_startproc
|
||||
save %sp, %o4, %sp
|
||||
cfi_def_cfa_register(%fp)
|
||||
cfi_window_save
|
||||
|
||||
sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
|
||||
add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of
|
||||
! frame to set up
|
||||
mov %i0, %o0 ! copy cif
|
||||
add %sp, STACK_BIAS+128+48, %o1 ! load args area
|
||||
mov %i2, %o2 ! copy rvalue
|
||||
call C(ffi_prep_args_v9)
|
||||
mov %i3, %o3 ! copy avalue
|
||||
|
||||
mov %l0, %o0 ! call routine to set up frame
|
||||
call %i0
|
||||
mov %i1, %o1 ! (delay)
|
||||
brz,pt %o0, 1f
|
||||
ldx [%l0+ARGS], %o0 ! call foreign function
|
||||
andcc %o0, SPARC_FLAG_FP_ARGS, %g0 ! need fp regs?
|
||||
add %sp, 48, %sp ! deallocate prep frame
|
||||
be,pt %xcc, 1f
|
||||
mov %o0, %l0 ! save flags
|
||||
|
||||
ldd [%l0+ARGS], %f0
|
||||
ldd [%l0+ARGS+8], %f2
|
||||
ldd [%l0+ARGS+16], %f4
|
||||
ldd [%l0+ARGS+24], %f6
|
||||
ldd [%l0+ARGS+32], %f8
|
||||
ldd [%l0+ARGS+40], %f10
|
||||
ldd [%l0+ARGS+48], %f12
|
||||
ldd [%l0+ARGS+56], %f14
|
||||
ldd [%l0+ARGS+64], %f16
|
||||
ldd [%l0+ARGS+72], %f18
|
||||
ldd [%l0+ARGS+80], %f20
|
||||
ldd [%l0+ARGS+88], %f22
|
||||
ldd [%l0+ARGS+96], %f24
|
||||
ldd [%l0+ARGS+104], %f26
|
||||
ldd [%l0+ARGS+112], %f28
|
||||
ldd [%l0+ARGS+120], %f30
|
||||
ldd [%sp+STACK_BIAS+128], %f0 ! load all fp arg regs
|
||||
ldd [%sp+STACK_BIAS+128+8], %f2
|
||||
ldd [%sp+STACK_BIAS+128+16], %f4
|
||||
ldd [%sp+STACK_BIAS+128+24], %f6
|
||||
ldd [%sp+STACK_BIAS+128+32], %f8
|
||||
ldd [%sp+STACK_BIAS+128+40], %f10
|
||||
ldd [%sp+STACK_BIAS+128+48], %f12
|
||||
ldd [%sp+STACK_BIAS+128+56], %f14
|
||||
ldd [%sp+STACK_BIAS+128+64], %f16
|
||||
ldd [%sp+STACK_BIAS+128+72], %f18
|
||||
ldd [%sp+STACK_BIAS+128+80], %f20
|
||||
ldd [%sp+STACK_BIAS+128+88], %f22
|
||||
ldd [%sp+STACK_BIAS+128+96], %f24
|
||||
ldd [%sp+STACK_BIAS+128+104], %f26
|
||||
ldd [%sp+STACK_BIAS+128+112], %f28
|
||||
ldd [%sp+STACK_BIAS+128+120], %f30
|
||||
|
||||
1: ldx [%l0+ARGS+8], %o1
|
||||
ldx [%l0+ARGS+16], %o2
|
||||
ldx [%l0+ARGS+24], %o3
|
||||
ldx [%l0+ARGS+32], %o4
|
||||
ldx [%l0+ARGS+40], %o5
|
||||
call %i5
|
||||
sub %l0, STACK_BIAS, %sp ! (delay) switch to frame
|
||||
1: ldx [%sp+STACK_BIAS+128], %o0 ! load all int arg regs
|
||||
ldx [%sp+STACK_BIAS+128+8], %o1
|
||||
ldx [%sp+STACK_BIAS+128+16], %o2
|
||||
ldx [%sp+STACK_BIAS+128+24], %o3
|
||||
ldx [%sp+STACK_BIAS+128+32], %o4
|
||||
ldx [%sp+STACK_BIAS+128+40], %o5
|
||||
call %i1
|
||||
mov %i5, %g5 ! load static chain
|
||||
|
||||
! If the return value pointer is NULL, assume no return value.
|
||||
brz,pn %i4, done
|
||||
0: call 1f ! load pc in %o7
|
||||
and %l0, SPARC_FLAG_RET_MASK, %l1
|
||||
1: sll %l1, 4, %l1
|
||||
add %o7, %l1, %o7 ! o7 = 0b + ret_type*16
|
||||
jmp %o7+(2f-0b)
|
||||
nop
|
||||
|
||||
cmp %i3, FFI_TYPE_INT
|
||||
be,a,pt %icc, done
|
||||
stx %o0, [%i4+0] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_FLOAT
|
||||
be,a,pn %icc, done
|
||||
st %f0, [%i4+0] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_DOUBLE
|
||||
be,a,pn %icc, done
|
||||
std %f0, [%i4+0] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_STRUCT
|
||||
be,pn %icc, dostruct
|
||||
|
||||
cmp %i3, FFI_TYPE_LONGDOUBLE
|
||||
bne,pt %icc, done
|
||||
.align 16
|
||||
2:
|
||||
E SPARC_RET_VOID
|
||||
return %i7+8
|
||||
nop
|
||||
std %f0, [%i4+0]
|
||||
std %f2, [%i4+8]
|
||||
E SPARC_RET_STRUCT
|
||||
add %sp, STACK_BIAS-64+128+48, %l2
|
||||
sub %sp, 64, %sp
|
||||
b 8f
|
||||
stx %o0, [%l2]
|
||||
E SPARC_RET_UINT8
|
||||
and %o0, 0xff, %i0
|
||||
return %i7+8
|
||||
stx %o0, [%o2]
|
||||
E SPARC_RET_SINT8
|
||||
sll %o0, 24, %o0
|
||||
sra %o0, 24, %i0
|
||||
return %i7+8
|
||||
stx %o0, [%o2]
|
||||
E SPARC_RET_UINT16
|
||||
sll %o0, 16, %o0
|
||||
srl %o0, 16, %i0
|
||||
return %i7+8
|
||||
stx %o0, [%o2]
|
||||
E SPARC_RET_SINT16
|
||||
sll %o0, 16, %o0
|
||||
sra %o0, 16, %i0
|
||||
return %i7+8
|
||||
stx %o0, [%o2]
|
||||
E SPARC_RET_UINT32
|
||||
srl %o0, 0, %i0
|
||||
return %i7+8
|
||||
stx %o0, [%o2]
|
||||
E SP_V9_RET_SINT32
|
||||
sra %o0, 0, %i0
|
||||
return %i7+8
|
||||
stx %o0, [%o2]
|
||||
E SPARC_RET_INT64
|
||||
stx %o0, [%i2]
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_INT128
|
||||
stx %o0, [%i2]
|
||||
stx %o1, [%i2+8]
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_F_8
|
||||
st %f7, [%i2+7*4]
|
||||
nop
|
||||
st %f6, [%i2+6*4]
|
||||
nop
|
||||
E SPARC_RET_F_6
|
||||
st %f5, [%i2+5*4]
|
||||
nop
|
||||
st %f4, [%i2+4*4]
|
||||
nop
|
||||
E SPARC_RET_F_4
|
||||
std %f2, [%i2+2*4]
|
||||
return %i7+8
|
||||
std %f0, [%o2]
|
||||
E SPARC_RET_F_2
|
||||
return %i7+8
|
||||
std %f0, [%o2]
|
||||
E SP_V9_RET_F_3
|
||||
st %f2, [%i2+2*4]
|
||||
nop
|
||||
st %f1, [%i2+1*4]
|
||||
nop
|
||||
E SPARC_RET_F_1
|
||||
return %i7+8
|
||||
st %f0, [%o2]
|
||||
|
||||
done: ret
|
||||
restore
|
||||
! Finish the SPARC_RET_STRUCT sequence.
|
||||
.align 8
|
||||
8: stx %o1, [%l2+8]
|
||||
stx %o2, [%l2+16]
|
||||
stx %o3, [%l2+24]
|
||||
std %f0, [%l2+32]
|
||||
std %f2, [%l2+40]
|
||||
std %f4, [%l2+48]
|
||||
std %f6, [%l2+56]
|
||||
|
||||
dostruct:
|
||||
/* This will not work correctly for unions. */
|
||||
stx %o0, [%i4+0]
|
||||
stx %o1, [%i4+8]
|
||||
stx %o2, [%i4+16]
|
||||
stx %o3, [%i4+24]
|
||||
std %f0, [%i4+32]
|
||||
std %f2, [%i4+40]
|
||||
std %f4, [%i4+48]
|
||||
std %f6, [%i4+56]
|
||||
ret
|
||||
restore
|
||||
.LLFE1:
|
||||
! Copy the structure into place.
|
||||
srl %l0, SPARC_SIZEMASK_SHIFT, %o0 ! load size_mask
|
||||
mov %i2, %o1 ! load dst
|
||||
mov %l2, %o2 ! load src_gp
|
||||
call C(ffi_struct_float_copy)
|
||||
add %l2, 32, %o3 ! load src_fp
|
||||
|
||||
.ffi_call_v9_end:
|
||||
.size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9
|
||||
return %i7+8
|
||||
nop
|
||||
|
||||
cfi_endproc
|
||||
.size C(ffi_call_v9), . - C(ffi_call_v9)
|
||||
|
||||
|
||||
#undef STACKFRAME
|
||||
@@ -138,15 +211,40 @@ dostruct:
|
||||
|
||||
Receives the closure argument in %g1. */
|
||||
|
||||
.text
|
||||
.align 8
|
||||
.globl ffi_closure_v9
|
||||
.globl C(ffi_go_closure_v9)
|
||||
.type C(ffi_go_closure_v9),@function
|
||||
FFI_HIDDEN(C(ffi_go_closure_v9))
|
||||
|
||||
ffi_closure_v9:
|
||||
.LLFB2:
|
||||
C(ffi_go_closure_v9):
|
||||
cfi_startproc
|
||||
save %sp, -STACKFRAME, %sp
|
||||
.LLCFI1:
|
||||
cfi_def_cfa_register(%fp)
|
||||
cfi_window_save
|
||||
|
||||
ldx [%g5+8], %o0
|
||||
ldx [%g5+16], %o1
|
||||
b 0f
|
||||
mov %g5, %o2
|
||||
|
||||
cfi_endproc
|
||||
.size C(ffi_go_closure_v9), . - C(ffi_go_closure_v9)
|
||||
|
||||
.align 8
|
||||
.globl C(ffi_closure_v9)
|
||||
.type C(ffi_closure_v9),@function
|
||||
FFI_HIDDEN(C(ffi_closure_v9))
|
||||
|
||||
C(ffi_closure_v9):
|
||||
cfi_startproc
|
||||
save %sp, -STACKFRAME, %sp
|
||||
cfi_def_cfa_register(%fp)
|
||||
cfi_window_save
|
||||
|
||||
ldx [%g1+FFI_TRAMPOLINE_SIZE], %o0
|
||||
ldx [%g1+FFI_TRAMPOLINE_SIZE+8], %o1
|
||||
ldx [%g1+FFI_TRAMPOLINE_SIZE+16], %o2
|
||||
0:
|
||||
! Store all of the potential argument registers in va_list format.
|
||||
stx %i0, [FP+128+0]
|
||||
stx %i1, [FP+128+8]
|
||||
@@ -174,134 +272,106 @@ ffi_closure_v9:
|
||||
std %f30, [FP-8]
|
||||
|
||||
! Call ffi_closure_sparc_inner to do the bulk of the work.
|
||||
mov %g1, %o0
|
||||
add %fp, STACK_BIAS-160, %o1
|
||||
add %fp, STACK_BIAS+128, %o2
|
||||
call ffi_closure_sparc_inner_v9
|
||||
add %fp, STACK_BIAS-128, %o3
|
||||
add %fp, STACK_BIAS-160, %o3
|
||||
add %fp, STACK_BIAS+128, %o4
|
||||
call C(ffi_closure_sparc_inner_v9)
|
||||
add %fp, STACK_BIAS-128, %o5
|
||||
|
||||
! Load up the return value in the proper type.
|
||||
! See ffi_prep_cif_machdep for the list of cases.
|
||||
cmp %o0, FFI_TYPE_VOID
|
||||
be,pn %icc, done1
|
||||
0: call 1f ! load pc in %o7
|
||||
and %o0, SPARC_FLAG_RET_MASK, %o0
|
||||
1: sll %o0, 4, %o0 ! o2 = i2 * 16
|
||||
add %o7, %o0, %o7 ! o7 = 0b + i2*16
|
||||
jmp %o7+(2f-0b)
|
||||
nop
|
||||
|
||||
cmp %o0, FFI_TYPE_INT
|
||||
be,pn %icc, integer
|
||||
|
||||
cmp %o0, FFI_TYPE_FLOAT
|
||||
be,a,pn %icc, done1
|
||||
ld [FP-160], %f0
|
||||
|
||||
cmp %o0, FFI_TYPE_DOUBLE
|
||||
be,a,pn %icc, done1
|
||||
ldd [FP-160], %f0
|
||||
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
cmp %o0, FFI_TYPE_LONGDOUBLE
|
||||
be,a,pn %icc, longdouble1
|
||||
ldd [FP-160], %f0
|
||||
#endif
|
||||
|
||||
! FFI_TYPE_STRUCT
|
||||
ldx [FP-152], %i1
|
||||
ldx [FP-144], %i2
|
||||
ldx [FP-136], %i3
|
||||
ldd [FP-160], %f0
|
||||
ldd [FP-152], %f2
|
||||
ldd [FP-144], %f4
|
||||
ldd [FP-136], %f6
|
||||
|
||||
integer:
|
||||
! Note that we cannot load the data in the delay slot of
|
||||
! the return insn because the data is in the stack frame
|
||||
! that is deallocated by the return.
|
||||
.align 16
|
||||
2:
|
||||
E SPARC_RET_VOID
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_STRUCT
|
||||
ldx [FP-160], %i0
|
||||
ldd [FP-160], %f0
|
||||
b 8f
|
||||
ldx [FP-152], %i1
|
||||
E SPARC_RET_UINT8
|
||||
ldub [FP-160+7], %i0
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_SINT8
|
||||
ldsb [FP-160+7], %i0
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_UINT16
|
||||
lduh [FP-160+6], %i0
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_SINT16
|
||||
ldsh [FP-160+6], %i0
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_UINT32
|
||||
lduw [FP-160+4], %i0
|
||||
return %i7+8
|
||||
nop
|
||||
E SP_V9_RET_SINT32
|
||||
ldsw [FP-160+4], %i0
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_INT64
|
||||
ldx [FP-160], %i0
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_INT128
|
||||
ldx [FP-160], %i0
|
||||
ldx [FP-160+8], %i1
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_F_8
|
||||
ld [FP-160+7*4], %f7
|
||||
nop
|
||||
ld [FP-160+6*4], %f6
|
||||
nop
|
||||
E SPARC_RET_F_6
|
||||
ld [FP-160+5*4], %f5
|
||||
nop
|
||||
ld [FP-160+4*4], %f4
|
||||
nop
|
||||
E SPARC_RET_F_4
|
||||
ldd [FP-160], %f0
|
||||
ldd [FP-160+8], %f2
|
||||
return %i7+8
|
||||
nop
|
||||
E SPARC_RET_F_2
|
||||
ldd [FP-160], %f0
|
||||
return %i7+8
|
||||
nop
|
||||
E SP_V9_RET_F_3
|
||||
ld [FP-160+2*4], %f2
|
||||
nop
|
||||
ld [FP-160+1*4], %f1
|
||||
nop
|
||||
E SPARC_RET_F_1
|
||||
ld [FP-160], %f0
|
||||
return %i7+8
|
||||
nop
|
||||
|
||||
done1:
|
||||
ret
|
||||
restore
|
||||
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
longdouble1:
|
||||
ldd [FP-152], %f2
|
||||
ret
|
||||
restore
|
||||
#endif
|
||||
.LLFE2:
|
||||
|
||||
.ffi_closure_v9_end:
|
||||
.size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9
|
||||
|
||||
#ifdef HAVE_RO_EH_FRAME
|
||||
.section ".eh_frame",#alloc
|
||||
#else
|
||||
.section ".eh_frame",#alloc,#write
|
||||
#endif
|
||||
.LLframe1:
|
||||
.uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
|
||||
.LLSCIE1:
|
||||
.uaword 0x0 ! CIE Identifier Tag
|
||||
.byte 0x1 ! CIE Version
|
||||
.ascii "zR\0" ! CIE Augmentation
|
||||
.byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
|
||||
.byte 0x78 ! sleb128 -8; CIE Data Alignment Factor
|
||||
.byte 0xf ! CIE RA Column
|
||||
.byte 0x1 ! uleb128 0x1; Augmentation size
|
||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
||||
.byte 0x1b ! FDE Encoding (pcrel sdata4)
|
||||
#else
|
||||
.byte 0x50 ! FDE Encoding (aligned absolute)
|
||||
#endif
|
||||
.byte 0xc ! DW_CFA_def_cfa
|
||||
.byte 0xe ! uleb128 0xe
|
||||
.byte 0xff,0xf ! uleb128 0x7ff
|
||||
.align 8
|
||||
.LLECIE1:
|
||||
.LLSFDE1:
|
||||
.uaword .LLEFDE1-.LLASFDE1 ! FDE Length
|
||||
.LLASFDE1:
|
||||
.uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
|
||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
||||
.uaword %r_disp32(.LLFB1)
|
||||
.uaword .LLFE1-.LLFB1 ! FDE address range
|
||||
#else
|
||||
.align 8
|
||||
.xword .LLFB1
|
||||
.uaxword .LLFE1-.LLFB1 ! FDE address range
|
||||
#endif
|
||||
.byte 0x0 ! uleb128 0x0; Augmentation size
|
||||
.byte 0x4 ! DW_CFA_advance_loc4
|
||||
.uaword .LLCFI0-.LLFB1
|
||||
.byte 0xd ! DW_CFA_def_cfa_register
|
||||
.byte 0x1e ! uleb128 0x1e
|
||||
.byte 0x2d ! DW_CFA_GNU_window_save
|
||||
.byte 0x9 ! DW_CFA_register
|
||||
.byte 0xf ! uleb128 0xf
|
||||
.byte 0x1f ! uleb128 0x1f
|
||||
.align 8
|
||||
.LLEFDE1:
|
||||
.LLSFDE2:
|
||||
.uaword .LLEFDE2-.LLASFDE2 ! FDE Length
|
||||
.LLASFDE2:
|
||||
.uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
|
||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
||||
.uaword %r_disp32(.LLFB2)
|
||||
.uaword .LLFE2-.LLFB2 ! FDE address range
|
||||
#else
|
||||
.align 8
|
||||
.xword .LLFB2
|
||||
.uaxword .LLFE2-.LLFB2 ! FDE address range
|
||||
#endif
|
||||
.byte 0x0 ! uleb128 0x0; Augmentation size
|
||||
.byte 0x4 ! DW_CFA_advance_loc4
|
||||
.uaword .LLCFI1-.LLFB2
|
||||
.byte 0xd ! DW_CFA_def_cfa_register
|
||||
.byte 0x1e ! uleb128 0x1e
|
||||
.byte 0x2d ! DW_CFA_GNU_window_save
|
||||
.byte 0x9 ! DW_CFA_register
|
||||
.byte 0xf ! uleb128 0xf
|
||||
.byte 0x1f ! uleb128 0x1f
|
||||
.align 8
|
||||
.LLEFDE2:
|
||||
#endif
|
||||
! Finish the SPARC_RET_STRUCT sequence.
|
||||
.align 8
|
||||
8: ldd [FP-152], %f2
|
||||
ldx [FP-144], %i2
|
||||
ldd [FP-144], %f4
|
||||
ldx [FP-136], %i3
|
||||
ldd [FP-136], %f6
|
||||
return %i7+8
|
||||
nop
|
||||
|
||||
cfi_endproc
|
||||
.size C(ffi_closure_v9), . - C(ffi_closure_v9)
|
||||
#endif /* SPARC64 */
|
||||
#ifdef __linux__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
|
||||
+564
-802
File diff suppressed because it is too large
Load Diff
+233
-96
@@ -32,6 +32,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include "internal64.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
@@ -62,10 +64,12 @@ struct register_args
|
||||
/* Registers for argument passing. */
|
||||
UINT64 gpr[MAX_GPR_REGS];
|
||||
union big_int_union sse[MAX_SSE_REGS];
|
||||
UINT64 rax; /* ssecount */
|
||||
UINT64 r10; /* static chain */
|
||||
};
|
||||
|
||||
extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
|
||||
void *raddr, void (*fnaddr)(void), unsigned ssecount);
|
||||
void *raddr, void (*fnaddr)(void)) FFI_HIDDEN;
|
||||
|
||||
/* All reference to register classes here is identical to the code in
|
||||
gcc/config/i386/i386.c. Do *not* change one without the other. */
|
||||
@@ -167,6 +171,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
do_integer:
|
||||
{
|
||||
size_t size = byte_offset + type->size;
|
||||
|
||||
@@ -188,7 +193,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
||||
}
|
||||
else if (size <= 16)
|
||||
{
|
||||
classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
|
||||
classes[0] = classes[1] = X86_64_INTEGER_CLASS;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
@@ -297,11 +302,42 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
||||
}
|
||||
return words;
|
||||
}
|
||||
case FFI_TYPE_COMPLEX:
|
||||
{
|
||||
ffi_type *inner = type->elements[0];
|
||||
switch (inner->type)
|
||||
{
|
||||
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_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
goto do_integer;
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
case FFI_TYPE_FLOAT:
|
||||
classes[0] = X86_64_SSE_CLASS;
|
||||
if (byte_offset % 8)
|
||||
{
|
||||
classes[1] = X86_64_SSESF_CLASS;
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
classes[0] = classes[1] = X86_64_SSEDF_CLASS;
|
||||
return 2;
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
classes[0] = X86_64_COMPLEX_X87_CLASS;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0; /* Never reached. */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Examine the argument and return set number of register required in each
|
||||
@@ -356,13 +392,57 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
{
|
||||
int gprcount, ssecount, i, avn, ngpr, nsse, flags;
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
size_t bytes, n;
|
||||
size_t bytes, n, rtype_size;
|
||||
ffi_type *rtype;
|
||||
|
||||
if (cif->abi != FFI_UNIX64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
gprcount = ssecount = 0;
|
||||
|
||||
flags = cif->rtype->type;
|
||||
if (flags != FFI_TYPE_VOID)
|
||||
rtype = cif->rtype;
|
||||
rtype_size = rtype->size;
|
||||
switch (rtype->type)
|
||||
{
|
||||
case FFI_TYPE_VOID:
|
||||
flags = UNIX64_RET_VOID;
|
||||
break;
|
||||
case FFI_TYPE_UINT8:
|
||||
flags = UNIX64_RET_UINT8;
|
||||
break;
|
||||
case FFI_TYPE_SINT8:
|
||||
flags = UNIX64_RET_SINT8;
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
flags = UNIX64_RET_UINT16;
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
flags = UNIX64_RET_SINT16;
|
||||
break;
|
||||
case FFI_TYPE_UINT32:
|
||||
flags = UNIX64_RET_UINT32;
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
flags = UNIX64_RET_SINT32;
|
||||
break;
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
flags = UNIX64_RET_INT64;
|
||||
break;
|
||||
case FFI_TYPE_POINTER:
|
||||
flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = UNIX64_RET_XMM32;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
flags = UNIX64_RET_XMM64;
|
||||
break;
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
flags = UNIX64_RET_X87;
|
||||
break;
|
||||
case FFI_TYPE_STRUCT:
|
||||
n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
|
||||
if (n == 0)
|
||||
{
|
||||
@@ -370,22 +450,62 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
memory is the first argument. Allocate a register for it. */
|
||||
gprcount++;
|
||||
/* We don't have to do anything in asm for the return. */
|
||||
flags = FFI_TYPE_VOID;
|
||||
flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM;
|
||||
}
|
||||
else if (flags == FFI_TYPE_STRUCT)
|
||||
else
|
||||
{
|
||||
/* Mark which registers the result appears in. */
|
||||
_Bool sse0 = SSE_CLASS_P (classes[0]);
|
||||
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
|
||||
if (sse0 && !sse1)
|
||||
flags |= 1 << 8;
|
||||
else if (!sse0 && sse1)
|
||||
flags |= 1 << 9;
|
||||
else if (sse0 && sse1)
|
||||
flags |= 1 << 10;
|
||||
/* Mark the true size of the structure. */
|
||||
flags |= cif->rtype->size << 12;
|
||||
|
||||
if (rtype_size == 4 && sse0)
|
||||
flags = UNIX64_RET_XMM32;
|
||||
else if (rtype_size == 8)
|
||||
flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
|
||||
else
|
||||
{
|
||||
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
|
||||
if (sse0 && sse1)
|
||||
flags = UNIX64_RET_ST_XMM0_XMM1;
|
||||
else if (sse0)
|
||||
flags = UNIX64_RET_ST_XMM0_RAX;
|
||||
else if (sse1)
|
||||
flags = UNIX64_RET_ST_RAX_XMM0;
|
||||
else
|
||||
flags = UNIX64_RET_ST_RAX_RDX;
|
||||
flags |= rtype_size << UNIX64_SIZE_SHIFT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FFI_TYPE_COMPLEX:
|
||||
switch (rtype->elements[0]->type)
|
||||
{
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
flags = UNIX64_RET_ST_RAX_RDX | (rtype_size << UNIX64_SIZE_SHIFT);
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = UNIX64_RET_XMM64;
|
||||
break;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT);
|
||||
break;
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
flags = UNIX64_RET_X87_2;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return FFI_BAD_TYPEDEF;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return FFI_BAD_TYPEDEF;
|
||||
}
|
||||
|
||||
/* Go over all arguments and determine the way they should be passed.
|
||||
@@ -412,44 +532,50 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
}
|
||||
}
|
||||
if (ssecount)
|
||||
flags |= 1 << 11;
|
||||
flags |= UNIX64_FLAG_XMM_ARGS;
|
||||
|
||||
cif->flags = flags;
|
||||
cif->bytes = (unsigned)ALIGN (bytes, 8);
|
||||
cif->bytes = ALIGN (bytes, 8);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
static void
|
||||
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
char *stack, *argp;
|
||||
ffi_type **arg_types;
|
||||
int gprcount, ssecount, ngpr, nsse, i, avn;
|
||||
_Bool ret_in_memory;
|
||||
int gprcount, ssecount, ngpr, nsse, i, avn, flags;
|
||||
struct register_args *reg_args;
|
||||
|
||||
/* Can't call 32-bit mode from 64-bit mode. */
|
||||
FFI_ASSERT (cif->abi == FFI_UNIX64);
|
||||
|
||||
/* If the return value is a struct and we don't have a return value
|
||||
address then we need to make one. Note the setting of flags to
|
||||
VOID above in ffi_prep_cif_machdep. */
|
||||
ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
|
||||
&& (cif->flags & 0xff) == FFI_TYPE_VOID);
|
||||
if (rvalue == NULL && ret_in_memory)
|
||||
rvalue = alloca (cif->rtype->size);
|
||||
address then we need to make one. Otherwise we can ignore it. */
|
||||
flags = cif->flags;
|
||||
if (rvalue == NULL)
|
||||
{
|
||||
if (flags & UNIX64_FLAG_RET_IN_MEM)
|
||||
rvalue = alloca (cif->rtype->size);
|
||||
else
|
||||
flags = UNIX64_RET_VOID;
|
||||
}
|
||||
|
||||
/* Allocate the space for the arguments, plus 4 words of temp space. */
|
||||
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
|
||||
reg_args = (struct register_args *) stack;
|
||||
argp = stack + sizeof (struct register_args);
|
||||
|
||||
reg_args->r10 = (uintptr_t) closure;
|
||||
|
||||
gprcount = ssecount = 0;
|
||||
|
||||
/* If the return value is passed in memory, add the pointer as the
|
||||
first integer argument. */
|
||||
if (ret_in_memory)
|
||||
if (flags & UNIX64_FLAG_RET_IN_MEM)
|
||||
reg_args->gpr[gprcount++] = (unsigned long) rvalue;
|
||||
|
||||
avn = cif->nargs;
|
||||
@@ -494,17 +620,17 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
switch (arg_types[i]->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
*(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
|
||||
reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
*(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
|
||||
reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
|
||||
break;
|
||||
case FFI_TYPE_SINT32:
|
||||
*(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
|
||||
reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
|
||||
break;
|
||||
default:
|
||||
reg_args->gpr[gprcount] = 0;
|
||||
memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8);
|
||||
memcpy (®_args->gpr[gprcount], a, size);
|
||||
}
|
||||
gprcount++;
|
||||
break;
|
||||
@@ -521,13 +647,27 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
}
|
||||
}
|
||||
}
|
||||
reg_args->rax = ssecount;
|
||||
|
||||
ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
|
||||
cif->flags, rvalue, fn, ssecount);
|
||||
flags, rvalue, fn);
|
||||
}
|
||||
|
||||
void
|
||||
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, NULL);
|
||||
}
|
||||
|
||||
extern void ffi_closure_unix64(void);
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, closure);
|
||||
}
|
||||
|
||||
extern void ffi_closure_unix64(void) FFI_HIDDEN;
|
||||
extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
@@ -536,29 +676,27 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
volatile unsigned short *tramp;
|
||||
static const unsigned char trampoline[16] = {
|
||||
/* leaq -0x7(%rip),%r10 # 0x0 */
|
||||
0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
|
||||
/* jmpq *0x3(%rip) # 0x10 */
|
||||
0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
|
||||
/* nopl (%rax) */
|
||||
0x0f, 0x1f, 0x00
|
||||
};
|
||||
void (*dest)(void);
|
||||
char *tramp = closure->tramp;
|
||||
|
||||
/* Sanity check on the cif ABI. */
|
||||
{
|
||||
int abi = cif->abi;
|
||||
if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
|
||||
return FFI_BAD_ABI;
|
||||
}
|
||||
if (cif->abi != FFI_UNIX64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
tramp = (volatile unsigned short *) &closure->tramp[0];
|
||||
if (cif->flags & UNIX64_FLAG_XMM_ARGS)
|
||||
dest = ffi_closure_unix64_sse;
|
||||
else
|
||||
dest = ffi_closure_unix64;
|
||||
|
||||
tramp[0] = 0xbb49; /* mov <code>, %r11 */
|
||||
*((unsigned long long * volatile) &tramp[1])
|
||||
= (unsigned long) ffi_closure_unix64;
|
||||
tramp[5] = 0xba49; /* mov <data>, %r10 */
|
||||
*((unsigned long long * volatile) &tramp[6])
|
||||
= (unsigned long) codeloc;
|
||||
|
||||
/* Set the carry bit iff the function uses any sse registers.
|
||||
This is clc or stc, together with the first byte of the jmp. */
|
||||
tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
|
||||
|
||||
tramp[11] = 0xe3ff; /* jmp *%r11 */
|
||||
memcpy (tramp, trampoline, sizeof(trampoline));
|
||||
*(UINT64 *)(tramp + 16) = (uintptr_t)dest;
|
||||
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
@@ -567,49 +705,29 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
int
|
||||
ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
|
||||
struct register_args *reg_args, char *argp)
|
||||
int FFI_HIDDEN
|
||||
ffi_closure_unix64_inner(ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *rvalue,
|
||||
struct register_args *reg_args,
|
||||
char *argp)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
void **avalue;
|
||||
ffi_type **arg_types;
|
||||
long i, avn;
|
||||
int gprcount, ssecount, ngpr, nsse;
|
||||
int ret;
|
||||
|
||||
cif = closure->cif;
|
||||
avalue = alloca(cif->nargs * sizeof(void *));
|
||||
gprcount = ssecount = 0;
|
||||
|
||||
ret = cif->rtype->type;
|
||||
if (ret != FFI_TYPE_VOID)
|
||||
{
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
size_t n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
|
||||
if (n == 0)
|
||||
{
|
||||
/* The return value goes in memory. Arrange for the closure
|
||||
return value to go directly back to the original caller. */
|
||||
rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++];
|
||||
/* We don't have to do anything in asm for the return. */
|
||||
ret = FFI_TYPE_VOID;
|
||||
}
|
||||
else if (ret == FFI_TYPE_STRUCT && n == 2)
|
||||
{
|
||||
/* Mark which register the second word of the structure goes in. */
|
||||
_Bool sse0 = SSE_CLASS_P (classes[0]);
|
||||
_Bool sse1 = SSE_CLASS_P (classes[1]);
|
||||
if (!sse0 && sse1)
|
||||
ret |= 1 << 8;
|
||||
else if (sse0 && !sse1)
|
||||
ret |= 1 << 9;
|
||||
}
|
||||
}
|
||||
int flags;
|
||||
|
||||
avn = cif->nargs;
|
||||
arg_types = cif->arg_types;
|
||||
flags = cif->flags;
|
||||
avalue = alloca(avn * sizeof(void *));
|
||||
gprcount = ssecount = 0;
|
||||
|
||||
if (flags & UNIX64_FLAG_RET_IN_MEM)
|
||||
rvalue = (void *)(uintptr_t)reg_args->gpr[gprcount++];
|
||||
|
||||
arg_types = cif->arg_types;
|
||||
for (i = 0; i < avn; ++i)
|
||||
{
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
@@ -667,10 +785,29 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
closure->fun (cif, rvalue, avalue, closure->user_data);
|
||||
fun (cif, rvalue, avalue, user_data);
|
||||
|
||||
/* Tell assembly how to perform return type promotions. */
|
||||
return ret;
|
||||
return flags;
|
||||
}
|
||||
|
||||
extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
|
||||
extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
|
||||
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*))
|
||||
{
|
||||
if (cif->abi != FFI_UNIX64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS
|
||||
? ffi_go_closure_unix64_sse
|
||||
: ffi_go_closure_unix64);
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
||||
+35
-48
@@ -76,44 +76,40 @@ typedef signed long ffi_sarg;
|
||||
#endif
|
||||
|
||||
typedef enum ffi_abi {
|
||||
#if defined(X86_WIN64)
|
||||
FFI_FIRST_ABI = 0,
|
||||
|
||||
/* ---- Intel x86 Win32 ---------- */
|
||||
#ifdef X86_WIN32
|
||||
FFI_SYSV,
|
||||
FFI_STDCALL,
|
||||
FFI_THISCALL,
|
||||
FFI_FASTCALL,
|
||||
FFI_MS_CDECL,
|
||||
FFI_PASCAL,
|
||||
FFI_REGISTER,
|
||||
FFI_LAST_ABI,
|
||||
#ifdef _MSC_VER
|
||||
FFI_DEFAULT_ABI = FFI_MS_CDECL
|
||||
#else
|
||||
FFI_DEFAULT_ABI = FFI_SYSV
|
||||
#endif
|
||||
|
||||
#elif defined(X86_WIN64)
|
||||
FFI_WIN64,
|
||||
FFI_LAST_ABI,
|
||||
FFI_DEFAULT_ABI = FFI_WIN64
|
||||
|
||||
#else
|
||||
/* ---- Intel x86 and AMD x86-64 - */
|
||||
FFI_SYSV,
|
||||
FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
|
||||
FFI_THISCALL,
|
||||
FFI_FASTCALL,
|
||||
FFI_STDCALL,
|
||||
FFI_PASCAL,
|
||||
FFI_REGISTER,
|
||||
#elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
|
||||
FFI_FIRST_ABI = 1,
|
||||
FFI_UNIX64,
|
||||
FFI_LAST_ABI,
|
||||
#if defined(__i386__) || defined(__i386)
|
||||
FFI_DEFAULT_ABI = FFI_SYSV
|
||||
#else
|
||||
FFI_DEFAULT_ABI = FFI_UNIX64
|
||||
#endif
|
||||
|
||||
#elif defined(X86_WIN32)
|
||||
FFI_FIRST_ABI = 0,
|
||||
FFI_SYSV = 1,
|
||||
FFI_STDCALL = 2,
|
||||
FFI_THISCALL = 3,
|
||||
FFI_FASTCALL = 4,
|
||||
FFI_MS_CDECL = 5,
|
||||
FFI_PASCAL = 6,
|
||||
FFI_REGISTER = 7,
|
||||
FFI_LAST_ABI,
|
||||
FFI_DEFAULT_ABI = FFI_MS_CDECL
|
||||
#else
|
||||
FFI_FIRST_ABI = 0,
|
||||
FFI_SYSV = 1,
|
||||
FFI_THISCALL = 3,
|
||||
FFI_FASTCALL = 4,
|
||||
FFI_STDCALL = 5,
|
||||
FFI_PASCAL = 6,
|
||||
FFI_REGISTER = 7,
|
||||
FFI_MS_CDECL = 8,
|
||||
FFI_LAST_ABI,
|
||||
FFI_DEFAULT_ABI = FFI_SYSV
|
||||
#endif
|
||||
} ffi_abi;
|
||||
#endif
|
||||
@@ -121,29 +117,20 @@ typedef enum ffi_abi {
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_GO_CLOSURES 1
|
||||
|
||||
#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
|
||||
#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
|
||||
#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
|
||||
#define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
|
||||
|
||||
#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
|
||||
#define FFI_TRAMPOLINE_SIZE 24
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
#if defined (X86_64) || defined(X86_WIN64) \
|
||||
|| (defined (__x86_64__) && defined (X86_DARWIN))
|
||||
# define FFI_TRAMPOLINE_SIZE 24
|
||||
# define FFI_NATIVE_RAW_API 0
|
||||
#else
|
||||
#ifdef X86_WIN32
|
||||
#define FFI_TRAMPOLINE_SIZE 52
|
||||
#else
|
||||
#ifdef X86_WIN64
|
||||
#define FFI_TRAMPOLINE_SIZE 29
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
#define FFI_NO_RAW_API 1
|
||||
#else
|
||||
#define FFI_TRAMPOLINE_SIZE 10
|
||||
#endif
|
||||
#endif
|
||||
#ifndef X86_WIN64
|
||||
#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
|
||||
#endif
|
||||
# define FFI_TRAMPOLINE_SIZE 12
|
||||
# define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffiw64.c - Copyright (c) 2014 Red Hat, Inc.
|
||||
|
||||
x86 win64 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>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef X86_WIN64
|
||||
|
||||
struct win64_call_frame
|
||||
{
|
||||
UINT64 rbp; /* 0 */
|
||||
UINT64 retaddr; /* 8 */
|
||||
UINT64 fn; /* 16 */
|
||||
UINT64 flags; /* 24 */
|
||||
UINT64 rvalue; /* 32 */
|
||||
};
|
||||
|
||||
extern void ffi_call_win64 (void *stack, struct win64_call_frame *,
|
||||
void *closure) FFI_HIDDEN;
|
||||
|
||||
ffi_status
|
||||
ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
{
|
||||
int flags, n;
|
||||
|
||||
if (cif->abi != FFI_WIN64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
flags = cif->rtype->type;
|
||||
switch (flags)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
flags = FFI_TYPE_STRUCT;
|
||||
break;
|
||||
case FFI_TYPE_COMPLEX:
|
||||
flags = FFI_TYPE_STRUCT;
|
||||
/* FALLTHRU */
|
||||
case FFI_TYPE_STRUCT:
|
||||
switch (cif->rtype->size)
|
||||
{
|
||||
case 8:
|
||||
flags = FFI_TYPE_UINT64;
|
||||
break;
|
||||
case 4:
|
||||
flags = FFI_TYPE_SMALL_STRUCT_4B;
|
||||
break;
|
||||
case 2:
|
||||
flags = FFI_TYPE_SMALL_STRUCT_2B;
|
||||
break;
|
||||
case 1:
|
||||
flags = FFI_TYPE_SMALL_STRUCT_1B;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cif->flags = flags;
|
||||
|
||||
/* Each argument either fits in a register, an 8 byte slot, or is
|
||||
passed by reference with the pointer in the 8 byte slot. */
|
||||
n = cif->nargs;
|
||||
n += (flags == FFI_TYPE_STRUCT);
|
||||
if (n < 4)
|
||||
n = 4;
|
||||
cif->bytes = n * 8;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
int i, j, n, flags;
|
||||
UINT64 *stack;
|
||||
size_t rsize;
|
||||
struct win64_call_frame *frame;
|
||||
|
||||
FFI_ASSERT(cif->abi == FFI_WIN64);
|
||||
|
||||
flags = cif->flags;
|
||||
rsize = 0;
|
||||
|
||||
/* If we have no return value for a structure, we need to create one.
|
||||
Otherwise we can ignore the return type entirely. */
|
||||
if (rvalue == NULL)
|
||||
{
|
||||
if (flags == FFI_TYPE_STRUCT)
|
||||
rsize = cif->rtype->size;
|
||||
else
|
||||
flags = FFI_TYPE_VOID;
|
||||
}
|
||||
|
||||
stack = alloca(cif->bytes + sizeof(struct win64_call_frame) + rsize);
|
||||
frame = (struct win64_call_frame *)((char *)stack + cif->bytes);
|
||||
if (rsize)
|
||||
rvalue = frame + 1;
|
||||
|
||||
frame->fn = (uintptr_t)fn;
|
||||
frame->flags = flags;
|
||||
frame->rvalue = (uintptr_t)rvalue;
|
||||
|
||||
j = 0;
|
||||
if (flags == FFI_TYPE_STRUCT)
|
||||
{
|
||||
stack[0] = (uintptr_t)rvalue;
|
||||
j = 1;
|
||||
}
|
||||
|
||||
for (i = 0, n = cif->nargs; i < n; ++i, ++j)
|
||||
{
|
||||
switch (cif->arg_types[i]->size)
|
||||
{
|
||||
case 8:
|
||||
stack[j] = *(UINT64 *)avalue[i];
|
||||
break;
|
||||
case 4:
|
||||
stack[j] = *(UINT32 *)avalue[i];
|
||||
break;
|
||||
case 2:
|
||||
stack[j] = *(UINT16 *)avalue[i];
|
||||
break;
|
||||
case 1:
|
||||
stack[j] = *(UINT8 *)avalue[i];
|
||||
break;
|
||||
default:
|
||||
stack[j] = (uintptr_t)avalue[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ffi_call_win64 (stack, frame, closure);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
extern void ffi_closure_win64(void) FFI_HIDDEN;
|
||||
extern void ffi_go_closure_win64(void) FFI_HIDDEN;
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
static const unsigned char trampoline[16] = {
|
||||
/* leaq -0x7(%rip),%r10 # 0x0 */
|
||||
0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
|
||||
/* jmpq *0x3(%rip) # 0x10 */
|
||||
0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
|
||||
/* nopl (%rax) */
|
||||
0x0f, 0x1f, 0x00
|
||||
};
|
||||
void *tramp = closure->tramp;
|
||||
|
||||
if (cif->abi != FFI_WIN64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
memcpy (tramp, trampoline, sizeof(trampoline));
|
||||
*(UINT64 *)(tramp + 16) = (uintptr_t)ffi_closure_win64;
|
||||
|
||||
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*))
|
||||
{
|
||||
if (cif->abi != FFI_WIN64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
closure->tramp = ffi_go_closure_win64;
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
struct win64_closure_frame
|
||||
{
|
||||
UINT64 rvalue[2];
|
||||
UINT64 fargs[4];
|
||||
UINT64 retaddr;
|
||||
UINT64 args[];
|
||||
};
|
||||
|
||||
int FFI_HIDDEN
|
||||
ffi_closure_win64_inner(ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
struct win64_closure_frame *frame)
|
||||
{
|
||||
void **avalue;
|
||||
void *rvalue;
|
||||
int i, n, nreg, flags;
|
||||
|
||||
avalue = alloca(cif->nargs * sizeof(void *));
|
||||
rvalue = frame->rvalue;
|
||||
nreg = 0;
|
||||
|
||||
/* When returning a structure, the address is in the first argument.
|
||||
We must also be prepared to return the same address in eax, so
|
||||
install that address in the frame and pretend we return a pointer. */
|
||||
flags = cif->flags;
|
||||
if (flags == FFI_TYPE_STRUCT)
|
||||
{
|
||||
rvalue = (void *)(uintptr_t)frame->args[0];
|
||||
frame->rvalue[0] = frame->args[0];
|
||||
nreg = 1;
|
||||
}
|
||||
|
||||
for (i = 0, n = cif->nargs; i < n; ++i, ++nreg)
|
||||
{
|
||||
size_t size = cif->arg_types[i]->size;
|
||||
size_t type = cif->arg_types[i]->type;
|
||||
void *a;
|
||||
|
||||
if (type == FFI_TYPE_DOUBLE || type == FFI_TYPE_FLOAT)
|
||||
{
|
||||
if (nreg < 4)
|
||||
a = &frame->fargs[nreg];
|
||||
else
|
||||
a = &frame->args[nreg];
|
||||
}
|
||||
else if (size == 1 || size == 2 || size == 4 || size == 8)
|
||||
a = &frame->args[nreg];
|
||||
else
|
||||
a = (void *)(uintptr_t)frame->args[nreg];
|
||||
|
||||
avalue[i] = a;
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
fun (cif, rvalue, avalue, user_data);
|
||||
return flags;
|
||||
}
|
||||
|
||||
#endif /* X86_WIN64 */
|
||||
@@ -1,463 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
freebsd.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc.
|
||||
Copyright (c) 2008 Björn König
|
||||
|
||||
X86 Foreign Function Interface for FreeBSD
|
||||
|
||||
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 __x86_64__
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
||||
.text
|
||||
|
||||
.globl ffi_prep_args
|
||||
|
||||
.align 4
|
||||
.globl ffi_call_SYSV
|
||||
.type ffi_call_SYSV,@function
|
||||
|
||||
ffi_call_SYSV:
|
||||
.LFB1:
|
||||
pushl %ebp
|
||||
.LCFI0:
|
||||
movl %esp,%ebp
|
||||
.LCFI1:
|
||||
/* Make room for all of the new args. */
|
||||
movl 16(%ebp),%ecx
|
||||
subl %ecx,%esp
|
||||
|
||||
/* Align the stack pointer to 16-bytes */
|
||||
andl $0xfffffff0, %esp
|
||||
|
||||
movl %esp,%eax
|
||||
|
||||
/* Place all of the ffi_prep_args in position */
|
||||
pushl 12(%ebp)
|
||||
pushl %eax
|
||||
call *8(%ebp)
|
||||
|
||||
/* Return stack to previous state and call the function */
|
||||
addl $8,%esp
|
||||
|
||||
call *28(%ebp)
|
||||
|
||||
/* Load %ecx with the return type code */
|
||||
movl 20(%ebp),%ecx
|
||||
|
||||
/* Protect %esi. We're going to pop it in the epilogue. */
|
||||
pushl %esi
|
||||
|
||||
/* If the return value pointer is NULL, assume no return value. */
|
||||
cmpl $0,24(%ebp)
|
||||
jne 0f
|
||||
|
||||
/* Even if there is no space for the return value, we are
|
||||
obliged to handle floating-point values. */
|
||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
||||
jne noretval
|
||||
fstp %st(0)
|
||||
|
||||
jmp epilogue
|
||||
|
||||
0:
|
||||
call 1f
|
||||
|
||||
.Lstore_table:
|
||||
.long noretval-.Lstore_table /* FFI_TYPE_VOID */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_INT */
|
||||
.long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */
|
||||
.long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */
|
||||
.long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
|
||||
.long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */
|
||||
.long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */
|
||||
.long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */
|
||||
.long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_UINT32 */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_SINT32 */
|
||||
.long retint64-.Lstore_table /* FFI_TYPE_UINT64 */
|
||||
.long retint64-.Lstore_table /* FFI_TYPE_SINT64 */
|
||||
.long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_POINTER */
|
||||
.long retstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */
|
||||
.long retstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */
|
||||
|
||||
1:
|
||||
pop %esi
|
||||
add (%esi, %ecx, 4), %esi
|
||||
jmp *%esi
|
||||
|
||||
/* Sign/zero extend as appropriate. */
|
||||
retsint8:
|
||||
movsbl %al, %eax
|
||||
jmp retint
|
||||
|
||||
retsint16:
|
||||
movswl %ax, %eax
|
||||
jmp retint
|
||||
|
||||
retuint8:
|
||||
movzbl %al, %eax
|
||||
jmp retint
|
||||
|
||||
retuint16:
|
||||
movzwl %ax, %eax
|
||||
jmp retint
|
||||
|
||||
retfloat:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
fstps (%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retdouble:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
fstpl (%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retlongdouble:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
fstpt (%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retint64:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movl %eax,0(%ecx)
|
||||
movl %edx,4(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retstruct1b:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movb %al,0(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retstruct2b:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movw %ax,0(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retint:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movl %eax,0(%ecx)
|
||||
|
||||
retstruct:
|
||||
/* Nothing to do! */
|
||||
|
||||
noretval:
|
||||
epilogue:
|
||||
popl %esi
|
||||
movl %ebp,%esp
|
||||
popl %ebp
|
||||
ret
|
||||
.LFE1:
|
||||
.ffi_call_SYSV_end:
|
||||
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
|
||||
|
||||
.align 4
|
||||
FFI_HIDDEN (ffi_closure_SYSV)
|
||||
.globl ffi_closure_SYSV
|
||||
.type ffi_closure_SYSV, @function
|
||||
|
||||
ffi_closure_SYSV:
|
||||
.LFB2:
|
||||
pushl %ebp
|
||||
.LCFI2:
|
||||
movl %esp, %ebp
|
||||
.LCFI3:
|
||||
subl $40, %esp
|
||||
leal -24(%ebp), %edx
|
||||
movl %edx, -12(%ebp) /* resp */
|
||||
leal 8(%ebp), %edx
|
||||
movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
|
||||
leal -12(%ebp), %edx
|
||||
movl %edx, (%esp) /* &resp */
|
||||
#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__
|
||||
call ffi_closure_SYSV_inner
|
||||
#else
|
||||
movl %ebx, 8(%esp)
|
||||
.LCFI7:
|
||||
call 1f
|
||||
1: popl %ebx
|
||||
addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
|
||||
call ffi_closure_SYSV_inner@PLT
|
||||
movl 8(%esp), %ebx
|
||||
#endif
|
||||
movl -12(%ebp), %ecx
|
||||
cmpl $FFI_TYPE_INT, %eax
|
||||
je .Lcls_retint
|
||||
|
||||
/* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
|
||||
FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
|
||||
cmpl $FFI_TYPE_UINT64, %eax
|
||||
jge 0f
|
||||
cmpl $FFI_TYPE_UINT8, %eax
|
||||
jge .Lcls_retint
|
||||
|
||||
0: cmpl $FFI_TYPE_FLOAT, %eax
|
||||
je .Lcls_retfloat
|
||||
cmpl $FFI_TYPE_DOUBLE, %eax
|
||||
je .Lcls_retdouble
|
||||
cmpl $FFI_TYPE_LONGDOUBLE, %eax
|
||||
je .Lcls_retldouble
|
||||
cmpl $FFI_TYPE_SINT64, %eax
|
||||
je .Lcls_retllong
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_1B, %eax
|
||||
je .Lcls_retstruct1b
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_2B, %eax
|
||||
je .Lcls_retstruct2b
|
||||
cmpl $FFI_TYPE_STRUCT, %eax
|
||||
je .Lcls_retstruct
|
||||
.Lcls_epilogue:
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
ret
|
||||
.Lcls_retint:
|
||||
movl (%ecx), %eax
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retfloat:
|
||||
flds (%ecx)
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retdouble:
|
||||
fldl (%ecx)
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retldouble:
|
||||
fldt (%ecx)
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retllong:
|
||||
movl (%ecx), %eax
|
||||
movl 4(%ecx), %edx
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retstruct1b:
|
||||
movsbl (%ecx), %eax
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retstruct2b:
|
||||
movswl (%ecx), %eax
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retstruct:
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
ret $4
|
||||
.LFE2:
|
||||
.size ffi_closure_SYSV, .-ffi_closure_SYSV
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
||||
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
|
||||
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
|
||||
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
|
||||
#define CIF_FLAGS_OFFSET 20
|
||||
|
||||
.align 4
|
||||
FFI_HIDDEN (ffi_closure_raw_SYSV)
|
||||
.globl ffi_closure_raw_SYSV
|
||||
.type ffi_closure_raw_SYSV, @function
|
||||
|
||||
ffi_closure_raw_SYSV:
|
||||
.LFB3:
|
||||
pushl %ebp
|
||||
.LCFI4:
|
||||
movl %esp, %ebp
|
||||
.LCFI5:
|
||||
pushl %esi
|
||||
.LCFI6:
|
||||
subl $36, %esp
|
||||
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
|
||||
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
|
||||
movl %edx, 12(%esp) /* user_data */
|
||||
leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
|
||||
movl %edx, 8(%esp) /* raw_args */
|
||||
leal -24(%ebp), %edx
|
||||
movl %edx, 4(%esp) /* &res */
|
||||
movl %esi, (%esp) /* cif */
|
||||
call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
|
||||
movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
|
||||
cmpl $FFI_TYPE_INT, %eax
|
||||
je .Lrcls_retint
|
||||
|
||||
/* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
|
||||
FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
|
||||
cmpl $FFI_TYPE_UINT64, %eax
|
||||
jge 0f
|
||||
cmpl $FFI_TYPE_UINT8, %eax
|
||||
jge .Lrcls_retint
|
||||
0:
|
||||
cmpl $FFI_TYPE_FLOAT, %eax
|
||||
je .Lrcls_retfloat
|
||||
cmpl $FFI_TYPE_DOUBLE, %eax
|
||||
je .Lrcls_retdouble
|
||||
cmpl $FFI_TYPE_LONGDOUBLE, %eax
|
||||
je .Lrcls_retldouble
|
||||
cmpl $FFI_TYPE_SINT64, %eax
|
||||
je .Lrcls_retllong
|
||||
.Lrcls_epilogue:
|
||||
addl $36, %esp
|
||||
popl %esi
|
||||
popl %ebp
|
||||
ret
|
||||
.Lrcls_retint:
|
||||
movl -24(%ebp), %eax
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retfloat:
|
||||
flds -24(%ebp)
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retdouble:
|
||||
fldl -24(%ebp)
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retldouble:
|
||||
fldt -24(%ebp)
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retllong:
|
||||
movl -24(%ebp), %eax
|
||||
movl -20(%ebp), %edx
|
||||
jmp .Lrcls_epilogue
|
||||
.LFE3:
|
||||
.size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV
|
||||
#endif
|
||||
|
||||
.section .eh_frame,EH_FRAME_FLAGS,@progbits
|
||||
.Lframe1:
|
||||
.long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
|
||||
.LSCIE1:
|
||||
.long 0x0 /* CIE Identifier Tag */
|
||||
.byte 0x1 /* CIE Version */
|
||||
#ifdef __PIC__
|
||||
.ascii "zR\0" /* CIE Augmentation */
|
||||
#else
|
||||
.ascii "\0" /* CIE Augmentation */
|
||||
#endif
|
||||
.byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
|
||||
.byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
|
||||
.byte 0x8 /* CIE RA Column */
|
||||
#ifdef __PIC__
|
||||
.byte 0x1 /* .uleb128 0x1; Augmentation size */
|
||||
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
|
||||
#endif
|
||||
.byte 0xc /* DW_CFA_def_cfa */
|
||||
.byte 0x4 /* .uleb128 0x4 */
|
||||
.byte 0x4 /* .uleb128 0x4 */
|
||||
.byte 0x88 /* DW_CFA_offset, column 0x8 */
|
||||
.byte 0x1 /* .uleb128 0x1 */
|
||||
.align 4
|
||||
.LECIE1:
|
||||
.LSFDE1:
|
||||
.long .LEFDE1-.LASFDE1 /* FDE Length */
|
||||
.LASFDE1:
|
||||
.long .LASFDE1-.Lframe1 /* FDE CIE offset */
|
||||
#ifdef __PIC__
|
||||
.long .LFB1-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB1 /* FDE initial location */
|
||||
#endif
|
||||
.long .LFE1-.LFB1 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI0-.LFB1
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI1-.LCFI0
|
||||
.byte 0xd /* DW_CFA_def_cfa_register */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
.align 4
|
||||
.LEFDE1:
|
||||
.LSFDE2:
|
||||
.long .LEFDE2-.LASFDE2 /* FDE Length */
|
||||
.LASFDE2:
|
||||
.long .LASFDE2-.Lframe1 /* FDE CIE offset */
|
||||
#ifdef __PIC__
|
||||
.long .LFB2-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB2
|
||||
#endif
|
||||
.long .LFE2-.LFB2 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI2-.LFB2
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI3-.LCFI2
|
||||
.byte 0xd /* DW_CFA_def_cfa_register */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI7-.LCFI3
|
||||
.byte 0x83 /* DW_CFA_offset, column 0x3 */
|
||||
.byte 0xa /* .uleb128 0xa */
|
||||
#endif
|
||||
.align 4
|
||||
.LEFDE2:
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
||||
.LSFDE3:
|
||||
.long .LEFDE3-.LASFDE3 /* FDE Length */
|
||||
.LASFDE3:
|
||||
.long .LASFDE3-.Lframe1 /* FDE CIE offset */
|
||||
#ifdef __PIC__
|
||||
.long .LFB3-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB3
|
||||
#endif
|
||||
.long .LFE3-.LFB3 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI4-.LFB3
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI5-.LCFI4
|
||||
.byte 0xd /* DW_CFA_def_cfa_register */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI6-.LCFI5
|
||||
.byte 0x86 /* DW_CFA_offset, column 0x6 */
|
||||
.byte 0x3 /* .uleb128 0x3 */
|
||||
.align 4
|
||||
.LEFDE3:
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* ifndef __x86_64__ */
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,23 @@
|
||||
#define X86_RET_FLOAT 0
|
||||
#define X86_RET_DOUBLE 1
|
||||
#define X86_RET_LDOUBLE 2
|
||||
#define X86_RET_SINT8 3
|
||||
#define X86_RET_SINT16 4
|
||||
#define X86_RET_UINT8 5
|
||||
#define X86_RET_UINT16 6
|
||||
#define X86_RET_INT64 7
|
||||
#define X86_RET_INT32 8
|
||||
#define X86_RET_VOID 9
|
||||
#define X86_RET_STRUCTPOP 10
|
||||
#define X86_RET_STRUCTARG 11
|
||||
#define X86_RET_STRUCT_1B 12
|
||||
#define X86_RET_STRUCT_2B 13
|
||||
#define X86_RET_UNUSED14 14
|
||||
#define X86_RET_UNUSED15 15
|
||||
|
||||
#define X86_RET_TYPE_MASK 15
|
||||
#define X86_RET_POP_SHIFT 4
|
||||
|
||||
#define R_EAX 0
|
||||
#define R_EDX 1
|
||||
#define R_ECX 2
|
||||
@@ -0,0 +1,22 @@
|
||||
#define UNIX64_RET_VOID 0
|
||||
#define UNIX64_RET_UINT8 1
|
||||
#define UNIX64_RET_UINT16 2
|
||||
#define UNIX64_RET_UINT32 3
|
||||
#define UNIX64_RET_SINT8 4
|
||||
#define UNIX64_RET_SINT16 5
|
||||
#define UNIX64_RET_SINT32 6
|
||||
#define UNIX64_RET_INT64 7
|
||||
#define UNIX64_RET_XMM32 8
|
||||
#define UNIX64_RET_XMM64 9
|
||||
#define UNIX64_RET_X87 10
|
||||
#define UNIX64_RET_X87_2 11
|
||||
#define UNIX64_RET_ST_XMM0_RAX 12
|
||||
#define UNIX64_RET_ST_RAX_XMM0 13
|
||||
#define UNIX64_RET_ST_XMM0_XMM1 14
|
||||
#define UNIX64_RET_ST_RAX_RDX 15
|
||||
|
||||
#define UNIX64_RET_LAST 15
|
||||
|
||||
#define UNIX64_FLAG_RET_IN_MEM (1 << 10)
|
||||
#define UNIX64_FLAG_XMM_ARGS (1 << 11)
|
||||
#define UNIX64_SIZE_SHIFT 12
|
||||
+631
-410
File diff suppressed because it is too large
Load Diff
+276
-298
@@ -30,8 +30,21 @@
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
#include "internal64.h"
|
||||
|
||||
.text
|
||||
.text
|
||||
|
||||
/* This macro allows the safe creation of jump tables without an
|
||||
actual table. The entry points into the table are all 8 bytes.
|
||||
The use of ORG asserts that we're at the correct location. */
|
||||
/* ??? The clang assembler doesn't handle .org with symbolic expressions. */
|
||||
.macro E index
|
||||
.align 8
|
||||
#ifndef __clang__
|
||||
.org 0b + \index * 8, 0x90
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
|
||||
void *raddr, void (*fnaddr)(void));
|
||||
@@ -40,12 +53,13 @@
|
||||
for this function. This has been allocated by ffi_call. We also
|
||||
deallocate some of the stack that has been alloca'd. */
|
||||
|
||||
.align 2
|
||||
.align 8
|
||||
.globl ffi_call_unix64
|
||||
.type ffi_call_unix64,@function
|
||||
FFI_HIDDEN(ffi_call_unix64)
|
||||
|
||||
ffi_call_unix64:
|
||||
.LUW0:
|
||||
cfi_startproc
|
||||
movq (%rsp), %r10 /* Load return address. */
|
||||
leaq (%rdi, %rsi), %rax /* Find local stack base. */
|
||||
movq %rdx, (%rax) /* Save flags. */
|
||||
@@ -53,24 +67,36 @@ ffi_call_unix64:
|
||||
movq %rbp, 16(%rax) /* Save old frame pointer. */
|
||||
movq %r10, 24(%rax) /* Relocate return address. */
|
||||
movq %rax, %rbp /* Finalize local stack frame. */
|
||||
.LUW1:
|
||||
|
||||
/* New stack frame based off rbp. This is a itty bit of unwind
|
||||
trickery in that the CFA *has* changed. There is no easy way
|
||||
to describe it correctly on entry to the function. Fortunately,
|
||||
it doesn't matter too much since at all points we can correctly
|
||||
unwind back to ffi_call. Note that the location to which we
|
||||
moved the return address is (the new) CFA-8, so from the
|
||||
perspective of the unwind info, it hasn't moved. */
|
||||
cfi_def_cfa(%rbp, 32)
|
||||
cfi_rel_offset(%rbp, 16)
|
||||
|
||||
movq %rdi, %r10 /* Save a copy of the register area. */
|
||||
movq %r8, %r11 /* Save a copy of the target fn. */
|
||||
movl %r9d, %eax /* Set number of SSE registers. */
|
||||
|
||||
/* Load up all argument registers. */
|
||||
movq (%r10), %rdi
|
||||
movq 8(%r10), %rsi
|
||||
movq 16(%r10), %rdx
|
||||
movq 24(%r10), %rcx
|
||||
movq 32(%r10), %r8
|
||||
movq 40(%r10), %r9
|
||||
movq 0x08(%r10), %rsi
|
||||
movq 0x10(%r10), %rdx
|
||||
movq 0x18(%r10), %rcx
|
||||
movq 0x20(%r10), %r8
|
||||
movq 0x28(%r10), %r9
|
||||
movl 0xb0(%r10), %eax
|
||||
testl %eax, %eax
|
||||
jnz .Lload_sse
|
||||
.Lret_from_load_sse:
|
||||
|
||||
/* Deallocate the reg arg area. */
|
||||
leaq 176(%r10), %rsp
|
||||
/* Deallocate the reg arg area, except for r10, then load via pop. */
|
||||
leaq 0xb8(%r10), %rsp
|
||||
popq %r10
|
||||
|
||||
/* Call the user function. */
|
||||
call *%r11
|
||||
@@ -81,352 +107,304 @@ ffi_call_unix64:
|
||||
movq 0(%rbp), %rcx /* Reload flags. */
|
||||
movq 8(%rbp), %rdi /* Reload raddr. */
|
||||
movq 16(%rbp), %rbp /* Reload old frame pointer. */
|
||||
.LUW2:
|
||||
cfi_remember_state
|
||||
cfi_def_cfa(%rsp, 8)
|
||||
cfi_restore(%rbp)
|
||||
|
||||
/* The first byte of the flags contains the FFI_TYPE. */
|
||||
cmpb $UNIX64_RET_LAST, %cl
|
||||
movzbl %cl, %r10d
|
||||
leaq .Lstore_table(%rip), %r11
|
||||
movslq (%r11, %r10, 4), %r10
|
||||
addq %r11, %r10
|
||||
leaq 0f(%rip), %r11
|
||||
ja 9f
|
||||
leaq (%r11, %r10, 8), %r10
|
||||
|
||||
/* Prep for the structure cases: scratch area in redzone. */
|
||||
leaq -20(%rsp), %rsi
|
||||
jmp *%r10
|
||||
|
||||
.Lstore_table:
|
||||
.long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */
|
||||
.long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */
|
||||
.long .Lst_float-.Lstore_table /* FFI_TYPE_FLOAT */
|
||||
.long .Lst_double-.Lstore_table /* FFI_TYPE_DOUBLE */
|
||||
.long .Lst_ldouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
|
||||
.long .Lst_uint8-.Lstore_table /* FFI_TYPE_UINT8 */
|
||||
.long .Lst_sint8-.Lstore_table /* FFI_TYPE_SINT8 */
|
||||
.long .Lst_uint16-.Lstore_table /* FFI_TYPE_UINT16 */
|
||||
.long .Lst_sint16-.Lstore_table /* FFI_TYPE_SINT16 */
|
||||
.long .Lst_uint32-.Lstore_table /* FFI_TYPE_UINT32 */
|
||||
.long .Lst_sint32-.Lstore_table /* FFI_TYPE_SINT32 */
|
||||
.long .Lst_int64-.Lstore_table /* FFI_TYPE_UINT64 */
|
||||
.long .Lst_int64-.Lstore_table /* FFI_TYPE_SINT64 */
|
||||
.long .Lst_struct-.Lstore_table /* FFI_TYPE_STRUCT */
|
||||
.long .Lst_int64-.Lstore_table /* FFI_TYPE_POINTER */
|
||||
|
||||
.align 2
|
||||
.Lst_void:
|
||||
.align 8
|
||||
0:
|
||||
E UNIX64_RET_VOID
|
||||
ret
|
||||
.align 2
|
||||
|
||||
.Lst_uint8:
|
||||
movzbq %al, %rax
|
||||
E UNIX64_RET_UINT8
|
||||
movzbl %al, %eax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 2
|
||||
.Lst_sint8:
|
||||
E UNIX64_RET_UINT16
|
||||
movzwl %ax, %eax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
E UNIX64_RET_UINT32
|
||||
movl %eax, %eax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
E UNIX64_RET_SINT8
|
||||
movsbq %al, %rax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 2
|
||||
.Lst_uint16:
|
||||
movzwq %ax, %rax
|
||||
movq %rax, (%rdi)
|
||||
.align 2
|
||||
.Lst_sint16:
|
||||
E UNIX64_RET_SINT16
|
||||
movswq %ax, %rax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 2
|
||||
.Lst_uint32:
|
||||
movl %eax, %eax
|
||||
movq %rax, (%rdi)
|
||||
.align 2
|
||||
.Lst_sint32:
|
||||
E UNIX64_RET_SINT32
|
||||
cltq
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 2
|
||||
.Lst_int64:
|
||||
E UNIX64_RET_INT64
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
|
||||
.align 2
|
||||
.Lst_float:
|
||||
movss %xmm0, (%rdi)
|
||||
E UNIX64_RET_XMM32
|
||||
movd %xmm0, (%rdi)
|
||||
ret
|
||||
.align 2
|
||||
.Lst_double:
|
||||
movsd %xmm0, (%rdi)
|
||||
E UNIX64_RET_XMM64
|
||||
movq %xmm0, (%rdi)
|
||||
ret
|
||||
.Lst_ldouble:
|
||||
E UNIX64_RET_X87
|
||||
fstpt (%rdi)
|
||||
ret
|
||||
|
||||
.align 2
|
||||
.Lst_struct:
|
||||
leaq -20(%rsp), %rsi /* Scratch area in redzone. */
|
||||
|
||||
/* We have to locate the values now, and since we don't want to
|
||||
write too much data into the user's return value, we spill the
|
||||
value to a 16 byte scratch area first. Bits 8, 9, and 10
|
||||
control where the values are located. Only one of the three
|
||||
bits will be set; see ffi_prep_cif_machdep for the pattern. */
|
||||
movd %xmm0, %r10
|
||||
movd %xmm1, %r11
|
||||
testl $0x100, %ecx
|
||||
cmovnz %rax, %rdx
|
||||
cmovnz %r10, %rax
|
||||
testl $0x200, %ecx
|
||||
cmovnz %r10, %rdx
|
||||
testl $0x400, %ecx
|
||||
cmovnz %r10, %rax
|
||||
cmovnz %r11, %rdx
|
||||
movq %rax, (%rsi)
|
||||
E UNIX64_RET_X87_2
|
||||
fstpt (%rdi)
|
||||
fstpt 16(%rdi)
|
||||
ret
|
||||
E UNIX64_RET_ST_XMM0_RAX
|
||||
movq %rax, 8(%rsi)
|
||||
jmp 3f
|
||||
E UNIX64_RET_ST_RAX_XMM0
|
||||
movq %xmm0, 8(%rsi)
|
||||
jmp 2f
|
||||
E UNIX64_RET_ST_XMM0_XMM1
|
||||
movq %xmm1, 8(%rsi)
|
||||
jmp 3f
|
||||
E UNIX64_RET_ST_RAX_RDX
|
||||
movq %rdx, 8(%rsi)
|
||||
|
||||
/* Bits 12-31 contain the true size of the structure. Copy from
|
||||
the scratch area to the true destination. */
|
||||
shrl $12, %ecx
|
||||
2: movq %rax, (%rsi)
|
||||
shrl $UNIX64_SIZE_SHIFT, %ecx
|
||||
rep movsb
|
||||
ret
|
||||
.align 8
|
||||
3: movq %xmm0, (%rsi)
|
||||
shrl $UNIX64_SIZE_SHIFT, %ecx
|
||||
rep movsb
|
||||
ret
|
||||
|
||||
9: call abort@PLT
|
||||
|
||||
/* Many times we can avoid loading any SSE registers at all.
|
||||
It's not worth an indirect jump to load the exact set of
|
||||
SSE registers needed; zero or all is a good compromise. */
|
||||
.align 2
|
||||
.LUW3:
|
||||
cfi_restore_state
|
||||
.Lload_sse:
|
||||
movdqa 48(%r10), %xmm0
|
||||
movdqa 64(%r10), %xmm1
|
||||
movdqa 80(%r10), %xmm2
|
||||
movdqa 96(%r10), %xmm3
|
||||
movdqa 112(%r10), %xmm4
|
||||
movdqa 128(%r10), %xmm5
|
||||
movdqa 144(%r10), %xmm6
|
||||
movdqa 160(%r10), %xmm7
|
||||
movdqa 0x30(%r10), %xmm0
|
||||
movdqa 0x40(%r10), %xmm1
|
||||
movdqa 0x50(%r10), %xmm2
|
||||
movdqa 0x60(%r10), %xmm3
|
||||
movdqa 0x70(%r10), %xmm4
|
||||
movdqa 0x80(%r10), %xmm5
|
||||
movdqa 0x90(%r10), %xmm6
|
||||
movdqa 0xa0(%r10), %xmm7
|
||||
jmp .Lret_from_load_sse
|
||||
|
||||
.LUW4:
|
||||
cfi_endproc
|
||||
.size ffi_call_unix64,.-ffi_call_unix64
|
||||
|
||||
/* 6 general registers, 8 vector registers,
|
||||
32 bytes of rvalue, 8 bytes of alignment. */
|
||||
#define ffi_closure_OFS_G 0
|
||||
#define ffi_closure_OFS_V (6*8)
|
||||
#define ffi_closure_OFS_RVALUE (ffi_closure_OFS_V + 8*16)
|
||||
#define ffi_closure_FS (ffi_closure_OFS_RVALUE + 32 + 8)
|
||||
|
||||
/* The location of rvalue within the red zone after deallocating the frame. */
|
||||
#define ffi_closure_RED_RVALUE (ffi_closure_OFS_RVALUE - ffi_closure_FS)
|
||||
|
||||
.align 2
|
||||
.globl ffi_closure_unix64
|
||||
.globl ffi_closure_unix64_sse
|
||||
.type ffi_closure_unix64_sse,@function
|
||||
FFI_HIDDEN(ffi_closure_unix64_sse)
|
||||
|
||||
ffi_closure_unix64_sse:
|
||||
cfi_startproc
|
||||
subq $ffi_closure_FS, %rsp
|
||||
/* Note clang bug 21515: adjust_cfa_offset error across endproc. */
|
||||
cfi_def_cfa_offset(ffi_closure_FS + 8)
|
||||
|
||||
movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp)
|
||||
movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp)
|
||||
movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp)
|
||||
movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp)
|
||||
movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp)
|
||||
movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp)
|
||||
movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp)
|
||||
movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp)
|
||||
jmp 0f
|
||||
|
||||
cfi_endproc
|
||||
.size ffi_closure_unix64_sse,.-ffi_closure_unix64_sse
|
||||
|
||||
.align 2
|
||||
.globl ffi_closure_unix64
|
||||
.type ffi_closure_unix64,@function
|
||||
FFI_HIDDEN(ffi_closure_unix64)
|
||||
|
||||
ffi_closure_unix64:
|
||||
.LUW5:
|
||||
/* The carry flag is set by the trampoline iff SSE registers
|
||||
are used. Don't clobber it before the branch instruction. */
|
||||
leaq -200(%rsp), %rsp
|
||||
.LUW6:
|
||||
movq %rdi, (%rsp)
|
||||
movq %rsi, 8(%rsp)
|
||||
movq %rdx, 16(%rsp)
|
||||
movq %rcx, 24(%rsp)
|
||||
movq %r8, 32(%rsp)
|
||||
movq %r9, 40(%rsp)
|
||||
jc .Lsave_sse
|
||||
.Lret_from_save_sse:
|
||||
cfi_startproc
|
||||
subq $ffi_closure_FS, %rsp
|
||||
/* Note clang bug 21515: adjust_cfa_offset error across endproc. */
|
||||
cfi_def_cfa_offset(ffi_closure_FS + 8)
|
||||
0:
|
||||
movq %rdi, ffi_closure_OFS_G+0x00(%rsp)
|
||||
movq %rsi, ffi_closure_OFS_G+0x08(%rsp)
|
||||
movq %rdx, ffi_closure_OFS_G+0x10(%rsp)
|
||||
movq %rcx, ffi_closure_OFS_G+0x18(%rsp)
|
||||
movq %r8, ffi_closure_OFS_G+0x20(%rsp)
|
||||
movq %r9, ffi_closure_OFS_G+0x28(%rsp)
|
||||
|
||||
movq %r10, %rdi
|
||||
leaq 176(%rsp), %rsi
|
||||
movq %rsp, %rdx
|
||||
leaq 208(%rsp), %rcx
|
||||
call ffi_closure_unix64_inner@PLT
|
||||
#ifdef __ILP32__
|
||||
movl FFI_TRAMPOLINE_SIZE(%r10), %edi /* Load cif */
|
||||
movl FFI_TRAMPOLINE_SIZE+4(%r10), %esi /* Load fun */
|
||||
movl FFI_TRAMPOLINE_SIZE+8(%r10), %edx /* Load user_data */
|
||||
#else
|
||||
movq FFI_TRAMPOLINE_SIZE(%r10), %rdi /* Load cif */
|
||||
movq FFI_TRAMPOLINE_SIZE+8(%r10), %rsi /* Load fun */
|
||||
movq FFI_TRAMPOLINE_SIZE+16(%r10), %rdx /* Load user_data */
|
||||
#endif
|
||||
.Ldo_closure:
|
||||
leaq ffi_closure_OFS_RVALUE(%rsp), %rcx /* Load rvalue */
|
||||
movq %rsp, %r8 /* Load reg_args */
|
||||
leaq ffi_closure_FS+8(%rsp), %r9 /* Load argp */
|
||||
call ffi_closure_unix64_inner
|
||||
|
||||
/* Deallocate stack frame early; return value is now in redzone. */
|
||||
addq $200, %rsp
|
||||
.LUW7:
|
||||
addq $ffi_closure_FS, %rsp
|
||||
cfi_adjust_cfa_offset(-ffi_closure_FS)
|
||||
|
||||
/* The first byte of the return value contains the FFI_TYPE. */
|
||||
cmpb $UNIX64_RET_LAST, %al
|
||||
movzbl %al, %r10d
|
||||
leaq .Lload_table(%rip), %r11
|
||||
movslq (%r11, %r10, 4), %r10
|
||||
addq %r11, %r10
|
||||
leaq 0f(%rip), %r11
|
||||
ja 9f
|
||||
leaq (%r11, %r10, 8), %r10
|
||||
leaq ffi_closure_RED_RVALUE(%rsp), %rsi
|
||||
jmp *%r10
|
||||
|
||||
.Lload_table:
|
||||
.long .Lld_void-.Lload_table /* FFI_TYPE_VOID */
|
||||
.long .Lld_int32-.Lload_table /* FFI_TYPE_INT */
|
||||
.long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */
|
||||
.long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */
|
||||
.long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */
|
||||
.long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */
|
||||
.long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */
|
||||
.long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */
|
||||
.long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */
|
||||
.long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */
|
||||
.long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */
|
||||
.long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */
|
||||
.long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */
|
||||
.long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */
|
||||
.long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */
|
||||
|
||||
.align 2
|
||||
.Lld_void:
|
||||
.align 8
|
||||
0:
|
||||
E UNIX64_RET_VOID
|
||||
ret
|
||||
E UNIX64_RET_UINT8
|
||||
movzbl (%rsi), %eax
|
||||
ret
|
||||
E UNIX64_RET_UINT16
|
||||
movzwl (%rsi), %eax
|
||||
ret
|
||||
E UNIX64_RET_UINT32
|
||||
movl (%rsi), %eax
|
||||
ret
|
||||
E UNIX64_RET_SINT8
|
||||
movsbl (%rsi), %eax
|
||||
ret
|
||||
E UNIX64_RET_SINT16
|
||||
movswl (%rsi), %eax
|
||||
ret
|
||||
E UNIX64_RET_SINT32
|
||||
movl (%rsi), %eax
|
||||
ret
|
||||
E UNIX64_RET_INT64
|
||||
movq (%rsi), %rax
|
||||
ret
|
||||
E UNIX64_RET_XMM32
|
||||
movd (%rsi), %xmm0
|
||||
ret
|
||||
E UNIX64_RET_XMM64
|
||||
movq (%rsi), %xmm0
|
||||
ret
|
||||
E UNIX64_RET_X87
|
||||
fldt (%rsi)
|
||||
ret
|
||||
E UNIX64_RET_X87_2
|
||||
fldt 16(%rsi)
|
||||
fldt (%rsi)
|
||||
ret
|
||||
E UNIX64_RET_ST_XMM0_RAX
|
||||
movq 8(%rsi), %rax
|
||||
jmp 3f
|
||||
E UNIX64_RET_ST_RAX_XMM0
|
||||
movq 8(%rsi), %xmm0
|
||||
jmp 2f
|
||||
E UNIX64_RET_ST_XMM0_XMM1
|
||||
movq 8(%rsi), %xmm1
|
||||
jmp 3f
|
||||
E UNIX64_RET_ST_RAX_RDX
|
||||
movq 8(%rsi), %rdx
|
||||
2: movq (%rsi), %rax
|
||||
ret
|
||||
.align 8
|
||||
3: movq (%rsi), %xmm0
|
||||
ret
|
||||
|
||||
.align 2
|
||||
.Lld_int8:
|
||||
movzbl -24(%rsp), %eax
|
||||
ret
|
||||
.align 2
|
||||
.Lld_int16:
|
||||
movzwl -24(%rsp), %eax
|
||||
ret
|
||||
.align 2
|
||||
.Lld_int32:
|
||||
movl -24(%rsp), %eax
|
||||
ret
|
||||
.align 2
|
||||
.Lld_int64:
|
||||
movq -24(%rsp), %rax
|
||||
ret
|
||||
9: call abort@PLT
|
||||
|
||||
.align 2
|
||||
.Lld_float:
|
||||
movss -24(%rsp), %xmm0
|
||||
ret
|
||||
.align 2
|
||||
.Lld_double:
|
||||
movsd -24(%rsp), %xmm0
|
||||
ret
|
||||
.align 2
|
||||
.Lld_ldouble:
|
||||
fldt -24(%rsp)
|
||||
ret
|
||||
|
||||
.align 2
|
||||
.Lld_struct:
|
||||
/* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
|
||||
%rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading
|
||||
both rdx and xmm1 with the second word. For the remaining,
|
||||
bit 8 set means xmm0 gets the second word, and bit 9 means
|
||||
that rax gets the second word. */
|
||||
movq -24(%rsp), %rcx
|
||||
movq -16(%rsp), %rdx
|
||||
movq -16(%rsp), %xmm1
|
||||
testl $0x100, %eax
|
||||
cmovnz %rdx, %rcx
|
||||
movd %rcx, %xmm0
|
||||
testl $0x200, %eax
|
||||
movq -24(%rsp), %rax
|
||||
cmovnz %rdx, %rax
|
||||
ret
|
||||
|
||||
/* See the comment above .Lload_sse; the same logic applies here. */
|
||||
.align 2
|
||||
.LUW8:
|
||||
.Lsave_sse:
|
||||
movdqa %xmm0, 48(%rsp)
|
||||
movdqa %xmm1, 64(%rsp)
|
||||
movdqa %xmm2, 80(%rsp)
|
||||
movdqa %xmm3, 96(%rsp)
|
||||
movdqa %xmm4, 112(%rsp)
|
||||
movdqa %xmm5, 128(%rsp)
|
||||
movdqa %xmm6, 144(%rsp)
|
||||
movdqa %xmm7, 160(%rsp)
|
||||
jmp .Lret_from_save_sse
|
||||
|
||||
.LUW9:
|
||||
cfi_endproc
|
||||
.size ffi_closure_unix64,.-ffi_closure_unix64
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* Only emit DWARF unwind info when building with the GNU toolchain. */
|
||||
.align 2
|
||||
.globl ffi_go_closure_unix64_sse
|
||||
.type ffi_go_closure_unix64_sse,@function
|
||||
FFI_HIDDEN(ffi_go_closure_unix64_sse)
|
||||
|
||||
#ifdef HAVE_AS_X86_64_UNWIND_SECTION_TYPE
|
||||
.section .eh_frame,"a",@unwind
|
||||
ffi_go_closure_unix64_sse:
|
||||
cfi_startproc
|
||||
subq $ffi_closure_FS, %rsp
|
||||
/* Note clang bug 21515: adjust_cfa_offset error across endproc. */
|
||||
cfi_def_cfa_offset(ffi_closure_FS + 8)
|
||||
|
||||
movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp)
|
||||
movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp)
|
||||
movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp)
|
||||
movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp)
|
||||
movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp)
|
||||
movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp)
|
||||
movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp)
|
||||
movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp)
|
||||
jmp 0f
|
||||
|
||||
cfi_endproc
|
||||
.size ffi_go_closure_unix64_sse,.-ffi_go_closure_unix64_sse
|
||||
|
||||
.align 2
|
||||
.globl ffi_go_closure_unix64
|
||||
.type ffi_go_closure_unix64,@function
|
||||
FFI_HIDDEN(ffi_go_closure_unix64)
|
||||
|
||||
ffi_go_closure_unix64:
|
||||
cfi_startproc
|
||||
subq $ffi_closure_FS, %rsp
|
||||
/* Note clang bug 21515: adjust_cfa_offset error across endproc. */
|
||||
cfi_def_cfa_offset(ffi_closure_FS + 8)
|
||||
0:
|
||||
movq %rdi, ffi_closure_OFS_G+0x00(%rsp)
|
||||
movq %rsi, ffi_closure_OFS_G+0x08(%rsp)
|
||||
movq %rdx, ffi_closure_OFS_G+0x10(%rsp)
|
||||
movq %rcx, ffi_closure_OFS_G+0x18(%rsp)
|
||||
movq %r8, ffi_closure_OFS_G+0x20(%rsp)
|
||||
movq %r9, ffi_closure_OFS_G+0x28(%rsp)
|
||||
|
||||
#ifdef __ILP32__
|
||||
movl 4(%r10), %edi /* Load cif */
|
||||
movl 8(%r10), %esi /* Load fun */
|
||||
movl %r10d, %edx /* Load closure (user_data) */
|
||||
#else
|
||||
.section .eh_frame,"a",@progbits
|
||||
movq 8(%r10), %rdi /* Load cif */
|
||||
movq 16(%r10), %rsi /* Load fun */
|
||||
movq %r10, %rdx /* Load closure (user_data) */
|
||||
#endif
|
||||
.Lframe1:
|
||||
.long .LECIE1-.LSCIE1 /* CIE Length */
|
||||
.LSCIE1:
|
||||
.long 0 /* CIE Identifier Tag */
|
||||
.byte 1 /* CIE Version */
|
||||
.ascii "zR\0" /* CIE Augmentation */
|
||||
.uleb128 1 /* CIE Code Alignment Factor */
|
||||
.sleb128 -8 /* CIE Data Alignment Factor */
|
||||
.byte 0x10 /* CIE RA Column */
|
||||
.uleb128 1 /* Augmentation size */
|
||||
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
|
||||
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
|
||||
.uleb128 7
|
||||
.uleb128 8
|
||||
.byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */
|
||||
.uleb128 1
|
||||
.align 8
|
||||
.LECIE1:
|
||||
.LSFDE1:
|
||||
.long .LEFDE1-.LASFDE1 /* FDE Length */
|
||||
.LASFDE1:
|
||||
.long .LASFDE1-.Lframe1 /* FDE CIE offset */
|
||||
#if HAVE_AS_X86_PCREL
|
||||
.long .LUW0-. /* FDE initial location */
|
||||
#else
|
||||
.long .LUW0@rel
|
||||
#endif
|
||||
.long .LUW4-.LUW0 /* FDE address range */
|
||||
.uleb128 0x0 /* Augmentation size */
|
||||
jmp .Ldo_closure
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LUW1-.LUW0
|
||||
cfi_endproc
|
||||
.size ffi_go_closure_unix64,.-ffi_go_closure_unix64
|
||||
|
||||
/* New stack frame based off rbp. This is a itty bit of unwind
|
||||
trickery in that the CFA *has* changed. There is no easy way
|
||||
to describe it correctly on entry to the function. Fortunately,
|
||||
it doesn't matter too much since at all points we can correctly
|
||||
unwind back to ffi_call. Note that the location to which we
|
||||
moved the return address is (the new) CFA-8, so from the
|
||||
perspective of the unwind info, it hasn't moved. */
|
||||
.byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */
|
||||
.uleb128 6
|
||||
.uleb128 32
|
||||
.byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */
|
||||
.uleb128 2
|
||||
.byte 0xa /* DW_CFA_remember_state */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LUW2-.LUW1
|
||||
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
|
||||
.uleb128 7
|
||||
.uleb128 8
|
||||
.byte 0xc0+6 /* DW_CFA_restore, %rbp */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LUW3-.LUW2
|
||||
.byte 0xb /* DW_CFA_restore_state */
|
||||
|
||||
.align 8
|
||||
.LEFDE1:
|
||||
.LSFDE3:
|
||||
.long .LEFDE3-.LASFDE3 /* FDE Length */
|
||||
.LASFDE3:
|
||||
.long .LASFDE3-.Lframe1 /* FDE CIE offset */
|
||||
#if HAVE_AS_X86_PCREL
|
||||
.long .LUW5-. /* FDE initial location */
|
||||
#else
|
||||
.long .LUW5@rel
|
||||
#endif
|
||||
.long .LUW9-.LUW5 /* FDE address range */
|
||||
.uleb128 0x0 /* Augmentation size */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LUW6-.LUW5
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset */
|
||||
.uleb128 208
|
||||
.byte 0xa /* DW_CFA_remember_state */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LUW7-.LUW6
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset */
|
||||
.uleb128 8
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LUW8-.LUW7
|
||||
.byte 0xb /* DW_CFA_restore_state */
|
||||
|
||||
.align 8
|
||||
.LEFDE3:
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
|
||||
-1351
File diff suppressed because it is too large
Load Diff
+192
-493
@@ -1,264 +1,16 @@
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
|
||||
/* Constants for ffi_call_win64 */
|
||||
#define STACK 0
|
||||
#define PREP_ARGS_FN 32
|
||||
#define ECIF 40
|
||||
#define CIF_BYTES 48
|
||||
#define CIF_FLAGS 56
|
||||
#define RVALUE 64
|
||||
#define FN 72
|
||||
#if defined(HAVE_AS_CFI_PSEUDO_OP)
|
||||
.cfi_sections .debug_frame
|
||||
#endif
|
||||
|
||||
/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *),
|
||||
extended_cif *ecif, unsigned bytes, unsigned flags,
|
||||
unsigned *rvalue, void (*fn)());
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
PUBLIC ffi_call_win64
|
||||
|
||||
EXTRN __chkstk:NEAR
|
||||
EXTRN ffi_closure_win64_inner:NEAR
|
||||
|
||||
_TEXT SEGMENT
|
||||
|
||||
;;; ffi_closure_win64 will be called with these registers set:
|
||||
;;; rax points to 'closure'
|
||||
;;; r11 contains a bit mask that specifies which of the
|
||||
;;; first four parameters are float or double
|
||||
;;;
|
||||
;;; It must move the parameters passed in registers to their stack location,
|
||||
;;; call ffi_closure_win64_inner for the actual work, then return the result.
|
||||
;;;
|
||||
ffi_closure_win64 PROC FRAME
|
||||
;; copy register arguments onto stack
|
||||
test r11, 1
|
||||
jne first_is_float
|
||||
mov QWORD PTR [rsp+8], rcx
|
||||
jmp second
|
||||
first_is_float:
|
||||
movlpd QWORD PTR [rsp+8], xmm0
|
||||
|
||||
second:
|
||||
test r11, 2
|
||||
jne second_is_float
|
||||
mov QWORD PTR [rsp+16], rdx
|
||||
jmp third
|
||||
second_is_float:
|
||||
movlpd QWORD PTR [rsp+16], xmm1
|
||||
|
||||
third:
|
||||
test r11, 4
|
||||
jne third_is_float
|
||||
mov QWORD PTR [rsp+24], r8
|
||||
jmp fourth
|
||||
third_is_float:
|
||||
movlpd QWORD PTR [rsp+24], xmm2
|
||||
|
||||
fourth:
|
||||
test r11, 8
|
||||
jne fourth_is_float
|
||||
mov QWORD PTR [rsp+32], r9
|
||||
jmp done
|
||||
fourth_is_float:
|
||||
movlpd QWORD PTR [rsp+32], xmm3
|
||||
|
||||
done:
|
||||
.ALLOCSTACK 40
|
||||
sub rsp, 40
|
||||
.ENDPROLOG
|
||||
mov rcx, rax ; context is first parameter
|
||||
mov rdx, rsp ; stack is second parameter
|
||||
add rdx, 48 ; point to start of arguments
|
||||
mov rax, ffi_closure_win64_inner
|
||||
call rax ; call the real closure function
|
||||
add rsp, 40
|
||||
movd xmm0, rax ; If the closure returned a float,
|
||||
; ffi_closure_win64_inner wrote it to rax
|
||||
ret 0
|
||||
ffi_closure_win64 ENDP
|
||||
|
||||
ffi_call_win64 PROC FRAME
|
||||
;; copy registers onto stack
|
||||
mov QWORD PTR [rsp+32], r9
|
||||
mov QWORD PTR [rsp+24], r8
|
||||
mov QWORD PTR [rsp+16], rdx
|
||||
mov QWORD PTR [rsp+8], rcx
|
||||
.PUSHREG rbp
|
||||
push rbp
|
||||
.ALLOCSTACK 48
|
||||
sub rsp, 48 ; 00000030H
|
||||
.SETFRAME rbp, 32
|
||||
lea rbp, QWORD PTR [rsp+32]
|
||||
.ENDPROLOG
|
||||
|
||||
mov eax, DWORD PTR CIF_BYTES[rbp]
|
||||
add rax, 15
|
||||
and rax, -16
|
||||
call __chkstk
|
||||
sub rsp, rax
|
||||
lea rax, QWORD PTR [rsp+32]
|
||||
mov QWORD PTR STACK[rbp], rax
|
||||
|
||||
mov rdx, QWORD PTR ECIF[rbp]
|
||||
mov rcx, QWORD PTR STACK[rbp]
|
||||
call QWORD PTR PREP_ARGS_FN[rbp]
|
||||
|
||||
mov rsp, QWORD PTR STACK[rbp]
|
||||
|
||||
movlpd xmm3, QWORD PTR [rsp+24]
|
||||
movd r9, xmm3
|
||||
|
||||
movlpd xmm2, QWORD PTR [rsp+16]
|
||||
movd r8, xmm2
|
||||
|
||||
movlpd xmm1, QWORD PTR [rsp+8]
|
||||
movd rdx, xmm1
|
||||
|
||||
movlpd xmm0, QWORD PTR [rsp]
|
||||
movd rcx, xmm0
|
||||
|
||||
call QWORD PTR FN[rbp]
|
||||
ret_struct4b$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B
|
||||
jne ret_struct2b$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
mov DWORD PTR [rcx], eax
|
||||
jmp ret_void$
|
||||
|
||||
ret_struct2b$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B
|
||||
jne ret_struct1b$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
mov WORD PTR [rcx], ax
|
||||
jmp ret_void$
|
||||
|
||||
ret_struct1b$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B
|
||||
jne ret_uint8$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
mov BYTE PTR [rcx], al
|
||||
jmp ret_void$
|
||||
|
||||
ret_uint8$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8
|
||||
jne ret_sint8$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
movzx rax, al
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp ret_void$
|
||||
|
||||
ret_sint8$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8
|
||||
jne ret_uint16$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
movsx rax, al
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp ret_void$
|
||||
|
||||
ret_uint16$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16
|
||||
jne ret_sint16$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
movzx rax, ax
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_sint16$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16
|
||||
jne ret_uint32$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
movsx rax, ax
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_uint32$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32
|
||||
jne ret_sint32$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
mov eax, eax
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_sint32$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32
|
||||
jne ret_float$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
cdqe
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_float$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT
|
||||
jne SHORT ret_double$
|
||||
|
||||
mov rax, QWORD PTR RVALUE[rbp]
|
||||
movss DWORD PTR [rax], xmm0
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_double$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE
|
||||
jne SHORT ret_uint64$
|
||||
|
||||
mov rax, QWORD PTR RVALUE[rbp]
|
||||
movlpd QWORD PTR [rax], xmm0
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_uint64$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT64
|
||||
jne SHORT ret_sint64$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_sint64$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64
|
||||
jne SHORT ret_pointer$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_pointer$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_POINTER
|
||||
jne SHORT ret_int$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_int$:
|
||||
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_INT
|
||||
jne SHORT ret_void$
|
||||
|
||||
mov rcx, QWORD PTR RVALUE[rbp]
|
||||
cdqe
|
||||
mov QWORD PTR [rcx], rax
|
||||
jmp SHORT ret_void$
|
||||
|
||||
ret_void$:
|
||||
xor rax, rax
|
||||
|
||||
lea rsp, QWORD PTR [rbp+16]
|
||||
pop rbp
|
||||
ret 0
|
||||
ffi_call_win64 ENDP
|
||||
_TEXT ENDS
|
||||
END
|
||||
|
||||
#else
|
||||
#define arg0 %rcx
|
||||
#define arg1 %rdx
|
||||
#define arg2 %r8
|
||||
#define arg3 %r9
|
||||
|
||||
#ifdef SYMBOL_UNDERSCORE
|
||||
#define SYMBOL_NAME(name) _##name
|
||||
@@ -266,255 +18,202 @@ END
|
||||
#define SYMBOL_NAME(name) name
|
||||
#endif
|
||||
|
||||
.text
|
||||
.macro E which
|
||||
.align 8
|
||||
.org 0b + \which * 8
|
||||
.endm
|
||||
|
||||
.extern SYMBOL_NAME(ffi_closure_win64_inner)
|
||||
.text
|
||||
|
||||
# ffi_closure_win64 will be called with these registers set:
|
||||
# rax points to 'closure'
|
||||
# r11 contains a bit mask that specifies which of the
|
||||
# first four parameters are float or double
|
||||
#
|
||||
# It must move the parameters passed in registers to their stack location,
|
||||
# call ffi_closure_win64_inner for the actual work, then return the result.
|
||||
#
|
||||
.balign 16
|
||||
.globl SYMBOL_NAME(ffi_closure_win64)
|
||||
.seh_proc SYMBOL_NAME(ffi_closure_win64)
|
||||
SYMBOL_NAME(ffi_closure_win64):
|
||||
# copy register arguments onto stack
|
||||
test $1,%r11
|
||||
jne .Lfirst_is_float
|
||||
mov %rcx, 8(%rsp)
|
||||
jmp .Lsecond
|
||||
.Lfirst_is_float:
|
||||
movlpd %xmm0, 8(%rsp)
|
||||
/* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10)
|
||||
|
||||
.Lsecond:
|
||||
test $2, %r11
|
||||
jne .Lsecond_is_float
|
||||
mov %rdx, 16(%rsp)
|
||||
jmp .Lthird
|
||||
.Lsecond_is_float:
|
||||
movlpd %xmm1, 16(%rsp)
|
||||
Bit o trickiness here -- FRAME is the base of the stack frame
|
||||
for this function. This has been allocated by ffi_call. We also
|
||||
deallocate some of the stack that has been alloca'd. */
|
||||
|
||||
.Lthird:
|
||||
test $4, %r11
|
||||
jne .Lthird_is_float
|
||||
mov %r8,24(%rsp)
|
||||
jmp .Lfourth
|
||||
.Lthird_is_float:
|
||||
movlpd %xmm2, 24(%rsp)
|
||||
.align 8
|
||||
.globl ffi_call_win64
|
||||
|
||||
.Lfourth:
|
||||
test $8, %r11
|
||||
jne .Lfourth_is_float
|
||||
mov %r9, 32(%rsp)
|
||||
jmp .Ldone
|
||||
.Lfourth_is_float:
|
||||
movlpd %xmm3, 32(%rsp)
|
||||
|
||||
.Ldone:
|
||||
.seh_stackalloc 40
|
||||
sub $40, %rsp
|
||||
.seh_proc ffi_call_win64
|
||||
ffi_call_win64:
|
||||
cfi_startproc
|
||||
/* Set up the local stack frame and install it in rbp/rsp. */
|
||||
movq (%rsp), %rax
|
||||
movq %rbp, (arg1)
|
||||
movq %rax, 8(arg1)
|
||||
movq arg1, %rbp
|
||||
cfi_def_cfa(%rbp, 16)
|
||||
cfi_rel_offset(%rbp, 0)
|
||||
.seh_pushreg %rbp
|
||||
.seh_setframe %rbp, 0
|
||||
.seh_endprologue
|
||||
mov %rax, %rcx # context is first parameter
|
||||
mov %rsp, %rdx # stack is second parameter
|
||||
add $48, %rdx # point to start of arguments
|
||||
leaq SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax
|
||||
callq *%rax # call the real closure function
|
||||
add $40, %rsp
|
||||
movq %rax, %xmm0 # If the closure returned a float,
|
||||
# ffi_closure_win64_inner wrote it to rax
|
||||
retq
|
||||
movq arg0, %rsp
|
||||
|
||||
movq arg2, %r10
|
||||
|
||||
/* Load all slots into both general and xmm registers. */
|
||||
movq (%rsp), %rcx
|
||||
movsd (%rsp), %xmm0
|
||||
movq 8(%rsp), %rdx
|
||||
movsd 8(%rsp), %xmm1
|
||||
movq 16(%rsp), %r8
|
||||
movsd 16(%rsp), %xmm2
|
||||
movq 24(%rsp), %r9
|
||||
movsd 24(%rsp), %xmm3
|
||||
|
||||
call *16(%rbp)
|
||||
|
||||
movl 24(%rbp), %ecx
|
||||
movq 32(%rbp), %r8
|
||||
leaq 0f(%rip), %r10
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_4B, %ecx
|
||||
leaq (%r10, %rcx, 8), %r10
|
||||
ja 99f
|
||||
jmp *%r10
|
||||
|
||||
/* Below, we're space constrained most of the time. Thus we eschew the
|
||||
modern "mov, pop, ret" sequence (5 bytes) for "leave, ret" (2 bytes). */
|
||||
.macro epilogue
|
||||
leaveq
|
||||
cfi_remember_state
|
||||
cfi_def_cfa(%rsp, 8)
|
||||
cfi_restore(%rbp)
|
||||
ret
|
||||
cfi_restore_state
|
||||
.endm
|
||||
|
||||
.align 8
|
||||
0:
|
||||
E FFI_TYPE_VOID
|
||||
epilogue
|
||||
E FFI_TYPE_INT
|
||||
movslq %eax, %rax
|
||||
movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_FLOAT
|
||||
movss %xmm0, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_DOUBLE
|
||||
movsd %xmm0, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_LONGDOUBLE
|
||||
call abort
|
||||
E FFI_TYPE_UINT8
|
||||
movzbl %al, %eax
|
||||
movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_SINT8
|
||||
movsbq %al, %rax
|
||||
jmp 98f
|
||||
E FFI_TYPE_UINT16
|
||||
movzwl %ax, %eax
|
||||
movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_SINT16
|
||||
movswq %ax, %rax
|
||||
jmp 98f
|
||||
E FFI_TYPE_UINT32
|
||||
movl %eax, %eax
|
||||
movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_SINT32
|
||||
movslq %eax, %rax
|
||||
movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_UINT64
|
||||
98: movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_SINT64
|
||||
movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_STRUCT
|
||||
epilogue
|
||||
E FFI_TYPE_POINTER
|
||||
movq %rax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_COMPLEX
|
||||
call abort
|
||||
E FFI_TYPE_SMALL_STRUCT_1B
|
||||
movb %al, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_SMALL_STRUCT_2B
|
||||
movw %ax, (%r8)
|
||||
epilogue
|
||||
E FFI_TYPE_SMALL_STRUCT_4B
|
||||
movl %eax, (%r8)
|
||||
epilogue
|
||||
|
||||
.align 8
|
||||
99: call abort
|
||||
|
||||
.purgem epilogue
|
||||
|
||||
cfi_endproc
|
||||
.seh_endproc
|
||||
|
||||
.balign 16
|
||||
.globl SYMBOL_NAME(ffi_call_win64)
|
||||
.seh_proc SYMBOL_NAME(ffi_call_win64)
|
||||
SYMBOL_NAME(ffi_call_win64):
|
||||
# copy registers onto stack
|
||||
mov %r9,32(%rsp)
|
||||
mov %r8,24(%rsp)
|
||||
mov %rdx,16(%rsp)
|
||||
mov %rcx,8(%rsp)
|
||||
.seh_pushreg rbp
|
||||
push %rbp
|
||||
.seh_stackalloc 48
|
||||
sub $48,%rsp
|
||||
.seh_setframe rbp, 32
|
||||
lea 32(%rsp),%rbp
|
||||
|
||||
/* 32 bytes of outgoing register stack space, 8 bytes of alignment,
|
||||
16 bytes of result, 32 bytes of xmm registers. */
|
||||
#define ffi_clo_FS (32+8+16+32)
|
||||
#define ffi_clo_OFF_R (32+8)
|
||||
#define ffi_clo_OFF_X (32+8+16)
|
||||
|
||||
.align 8
|
||||
.globl ffi_go_closure_win64
|
||||
|
||||
.seh_proc ffi_go_closure_win64
|
||||
ffi_go_closure_win64:
|
||||
cfi_startproc
|
||||
/* Save all integer arguments into the incoming reg stack space. */
|
||||
movq arg0, 8(%rsp)
|
||||
movq arg1, 16(%rsp)
|
||||
movq arg2, 24(%rsp)
|
||||
movq arg3, 32(%rsp)
|
||||
|
||||
movq 8(%r10), arg0 /* load cif */
|
||||
movq 16(%r10), arg1 /* load fun */
|
||||
movq %r10, arg2 /* closure is user_data */
|
||||
jmp 0f
|
||||
cfi_endproc
|
||||
.seh_endproc
|
||||
|
||||
.align 8
|
||||
.globl ffi_closure_win64
|
||||
|
||||
.seh_proc ffi_closure_win64
|
||||
ffi_closure_win64:
|
||||
cfi_startproc
|
||||
/* Save all integer arguments into the incoming reg stack space. */
|
||||
movq arg0, 8(%rsp)
|
||||
movq arg1, 16(%rsp)
|
||||
movq arg2, 24(%rsp)
|
||||
movq arg3, 32(%rsp)
|
||||
|
||||
movq FFI_TRAMPOLINE_SIZE(%r10), arg0 /* load cif */
|
||||
movq FFI_TRAMPOLINE_SIZE+8(%r10), arg1 /* load fun */
|
||||
movq FFI_TRAMPOLINE_SIZE+16(%r10), arg2 /* load user_data */
|
||||
0:
|
||||
subq $ffi_clo_FS, %rsp
|
||||
cfi_adjust_cfa_offset(ffi_clo_FS)
|
||||
.seh_stackalloc ffi_clo_FS
|
||||
.seh_endprologue
|
||||
|
||||
mov CIF_BYTES(%rbp),%eax
|
||||
add $15, %rax
|
||||
and $-16, %rax
|
||||
cmpq $0x1000, %rax
|
||||
jb Lch_done
|
||||
Lch_probe:
|
||||
subq $0x1000,%rsp
|
||||
orl $0x0, (%rsp)
|
||||
subq $0x1000,%rax
|
||||
cmpq $0x1000,%rax
|
||||
ja Lch_probe
|
||||
Lch_done:
|
||||
subq %rax, %rsp
|
||||
orl $0x0, (%rsp)
|
||||
lea 32(%rsp), %rax
|
||||
mov %rax, STACK(%rbp)
|
||||
/* Save all sse arguments into the stack frame. */
|
||||
movsd %xmm0, ffi_clo_OFF_X(%rsp)
|
||||
movsd %xmm1, ffi_clo_OFF_X+8(%rsp)
|
||||
movsd %xmm2, ffi_clo_OFF_X+16(%rsp)
|
||||
movsd %xmm3, ffi_clo_OFF_X+24(%rsp)
|
||||
|
||||
mov ECIF(%rbp), %rdx
|
||||
mov STACK(%rbp), %rcx
|
||||
callq *PREP_ARGS_FN(%rbp)
|
||||
leaq ffi_clo_OFF_R(%rsp), arg3
|
||||
call ffi_closure_win64_inner
|
||||
|
||||
mov STACK(%rbp), %rsp
|
||||
/* Load the result into both possible result registers. */
|
||||
movq ffi_clo_OFF_R(%rsp), %rax
|
||||
movsd ffi_clo_OFF_R(%rsp), %xmm0
|
||||
|
||||
movlpd 24(%rsp), %xmm3
|
||||
movd %xmm3, %r9
|
||||
addq $ffi_clo_FS, %rsp
|
||||
cfi_adjust_cfa_offset(-ffi_clo_FS)
|
||||
ret
|
||||
|
||||
movlpd 16(%rsp), %xmm2
|
||||
movd %xmm2, %r8
|
||||
|
||||
movlpd 8(%rsp), %xmm1
|
||||
movd %xmm1, %rdx
|
||||
|
||||
movlpd (%rsp), %xmm0
|
||||
movd %xmm0, %rcx
|
||||
|
||||
callq *FN(%rbp)
|
||||
.Lret_struct4b:
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp)
|
||||
jne .Lret_struct2b
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
mov %eax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_struct2b:
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp)
|
||||
jne .Lret_struct1b
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
mov %ax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_struct1b:
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp)
|
||||
jne .Lret_uint8
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
mov %al, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_uint8:
|
||||
cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp)
|
||||
jne .Lret_sint8
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
movzbq %al, %rax
|
||||
movq %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_sint8:
|
||||
cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp)
|
||||
jne .Lret_uint16
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
movsbq %al, %rax
|
||||
movq %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_uint16:
|
||||
cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp)
|
||||
jne .Lret_sint16
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
movzwq %ax, %rax
|
||||
movq %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_sint16:
|
||||
cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp)
|
||||
jne .Lret_uint32
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
movswq %ax, %rax
|
||||
movq %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_uint32:
|
||||
cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
|
||||
jne .Lret_sint32
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
movl %eax, %eax
|
||||
movq %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_sint32:
|
||||
cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp)
|
||||
jne .Lret_float
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
cltq
|
||||
movq %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_float:
|
||||
cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp)
|
||||
jne .Lret_double
|
||||
|
||||
mov RVALUE(%rbp), %rax
|
||||
movss %xmm0, (%rax)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_double:
|
||||
cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp)
|
||||
jne .Lret_uint64
|
||||
|
||||
mov RVALUE(%rbp), %rax
|
||||
movlpd %xmm0, (%rax)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_uint64:
|
||||
cmpl $FFI_TYPE_UINT64, CIF_FLAGS(%rbp)
|
||||
jne .Lret_sint64
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
mov %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_sint64:
|
||||
cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp)
|
||||
jne .Lret_pointer
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
mov %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_pointer:
|
||||
cmpl $FFI_TYPE_POINTER, CIF_FLAGS(%rbp)
|
||||
jne .Lret_int
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
mov %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_int:
|
||||
cmpl $FFI_TYPE_INT, CIF_FLAGS(%rbp)
|
||||
jne .Lret_void
|
||||
|
||||
mov RVALUE(%rbp), %rcx
|
||||
cltq
|
||||
movq %rax, (%rcx)
|
||||
jmp .Lret_void
|
||||
|
||||
.Lret_void:
|
||||
xor %rax, %rax
|
||||
|
||||
lea 16(%rbp), %rsp
|
||||
pop %rbp
|
||||
retq
|
||||
cfi_endproc
|
||||
.seh_endproc
|
||||
#endif /* !_MSC_VER */
|
||||
|
||||
|
||||
@@ -24,16 +24,20 @@ set ctlist [lsearch -inline -all -glob [lsort [glob -nocomplain -- $srcdir/$subd
|
||||
|
||||
run-many-tests $tlist ""
|
||||
|
||||
if { ![istarget s390*] } {
|
||||
|
||||
# ??? We really should preprocess ffi.h and grep
|
||||
# for FFI_TARGET_HAS_COMPLEX_TYPE.
|
||||
if { [istarget aarch64*]
|
||||
|| [istarget alpha*]
|
||||
|| [istarget arm*]
|
||||
|| [istarget i?86*]
|
||||
|| [istarget s390*]
|
||||
|| [istarget sparc*]
|
||||
|| [istarget x86_64*] } {
|
||||
run-many-tests $ctlist ""
|
||||
} else {
|
||||
foreach test $ctlist {
|
||||
unsupported "$test"
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
run-many-tests $ctlist ""
|
||||
|
||||
}
|
||||
|
||||
dg-finish
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
PR: none.
|
||||
Originator: <hos@tamanegi.org> 20031203 */
|
||||
|
||||
/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
|
||||
#include "ffitest.h"
|
||||
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
Originator: Blake Chaffin 6/18/2007
|
||||
*/
|
||||
|
||||
/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-do run { xfail strongarm*-*-* } } */
|
||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
|
||||
#include "ffitest.h"
|
||||
|
||||
|
||||
@@ -6,5 +6,11 @@
|
||||
|
||||
/* { dg-do run } */
|
||||
|
||||
/* Alpha splits _Complex into two arguments. It's illegal to pass
|
||||
float through varargs, so _Complex float goes badly. In sort of
|
||||
gets passed as _Complex double, but the compiler doesn't agree
|
||||
with itself on this issue. */
|
||||
/* { dg-do run { xfail alpha*-*-* } } */
|
||||
|
||||
#include "complex_defs_float.inc"
|
||||
#include "cls_complex_va.inc"
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
PR: none.
|
||||
Originator: Blake Chaffin */
|
||||
|
||||
/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* This test is known to PASS on armv7l-unknown-linux-gnueabihf, so I have
|
||||
remove the xfail for arm*-*-* below, until we know more. */
|
||||
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
|
||||
#include "ffitest.h"
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
_Complex int f_complex(_Complex int c, int x, int *py)
|
||||
{
|
||||
c = -(2 * creal (c)) + (cimag (c) + 1)* I;
|
||||
__real__ c = -2 * __real__ c;
|
||||
__imag__ c = __imag__ c + 1;
|
||||
*py += x;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
Limitations: none.
|
||||
PR: none.
|
||||
Originator: From the original ffitest.c */
|
||||
|
||||
/* { dg-excess-errors "fails" { target x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-do run } */
|
||||
|
||||
#include "ffitest.h"
|
||||
#include "float.h"
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
Originator: Blake Chaffin 6/18/2007
|
||||
*/
|
||||
|
||||
/* { dg-excess-errors "" { target x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||
/* { dg-options -Wformat=0 { target moxie*-*-elf } } */
|
||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
|
||||
#include "ffitest.h"
|
||||
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
#include "ffitest.h"
|
||||
#include <complex.h>
|
||||
|
||||
static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c1, _Complex T_C_TYPE c2, unsigned int in3, _Complex T_C_TYPE c4)
|
||||
_Complex T_C_TYPE
|
||||
return_c(_Complex T_C_TYPE c1, _Complex T_C_TYPE c2,
|
||||
unsigned int in3, _Complex T_C_TYPE c4)
|
||||
{
|
||||
return c1 + c2 + in3 + c4;
|
||||
volatile _Complex T_C_TYPE r = c1 + c2 + in3 + c4;
|
||||
return r;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
ffi_cif cif;
|
||||
@@ -35,6 +39,6 @@ int main (void)
|
||||
printf ("%f,%fi vs %f,%fi\n",
|
||||
T_CONV creal (rc), T_CONV cimag (rc),
|
||||
T_CONV creal (rc2), T_CONV cimag (rc2));
|
||||
CHECK(rc == c1 + c2 + in3 + c4);
|
||||
CHECK(rc == rc2);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
Limitations: none.
|
||||
PR: none.
|
||||
Originator: <andreast@gcc.gnu.org> 20071113 */
|
||||
/* { dg-do run } */
|
||||
|
||||
/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
#include "ffitest.h"
|
||||
|
||||
static long double return_ldl(long double ldl)
|
||||
|
||||
Reference in New Issue
Block a user