mirror of
https://github.com/partic2/libffi
synced 2026-11-11 10:37:19 +00:00
Merge branch 'go-closure' of https://github.com/rth7680/libffi into rth7680-go-closure
Conflicts: src/aarch64/ffi.c
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/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/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \
|
||||||
src/sparc/v9.S src/sparc/ffitarget.h src/sparc/ffi.c \
|
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/sparc/ffi64.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/darwin.S src/x86/ffiw64.c src/x86/win64.S \
|
||||||
src/x86/freebsd.S src/x86/ffi64.c src/x86/unix64.S \
|
src/x86/ffi64.c src/x86/unix64.S \
|
||||||
src/x86/ffitarget.h src/pa/ffitarget.h src/pa/ffi.c \
|
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/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 \
|
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 \
|
src/xtensa/ffitarget.h src/xtensa/ffi.c src/xtensa/sysv.S \
|
||||||
ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \
|
ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \
|
||||||
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.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 \
|
generate-darwin-source-and-headers.py \
|
||||||
libffi.xcodeproj/project.pbxproj src/arm/trampoline.S \
|
libffi.xcodeproj/project.pbxproj \
|
||||||
libtool-ldflags ChangeLog.libffi-3.1
|
libtool-ldflags ChangeLog.libffi-3.1
|
||||||
|
|
||||||
info_TEXINFOS = doc/libffi.texi
|
info_TEXINFOS = doc/libffi.texi
|
||||||
@@ -126,25 +126,22 @@ if BFIN
|
|||||||
nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S
|
nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S
|
||||||
endif
|
endif
|
||||||
if X86
|
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
|
endif
|
||||||
if X86_FREEBSD
|
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
|
endif
|
||||||
if X86_WIN32
|
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
|
endif
|
||||||
if X86_WIN64
|
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
|
endif
|
||||||
if X86_DARWIN
|
if X86_DARWIN
|
||||||
nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S
|
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
|
endif
|
||||||
if SPARC
|
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
|
endif
|
||||||
if ALPHA
|
if ALPHA
|
||||||
nodist_libffi_la_SOURCES += src/alpha/ffi.c src/alpha/osf.S
|
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
|
endif
|
||||||
if ARM
|
if ARM
|
||||||
nodist_libffi_la_SOURCES += src/arm/sysv.S src/arm/ffi.c
|
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
|
endif
|
||||||
if AVR32
|
if AVR32
|
||||||
nodist_libffi_la_SOURCES += src/avr32/sysv.S src/avr32/ffi.c
|
nodist_libffi_la_SOURCES += src/avr32/sysv.S src/avr32/ffi.c
|
||||||
|
|||||||
@@ -428,6 +428,22 @@ ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
|
|||||||
|
|
||||||
#endif /* FFI_CLOSURES */
|
#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 -------------------------------------- */
|
/* ---- Public interface definition -------------------------------------- */
|
||||||
|
|
||||||
ffi_status ffi_prep_cif(ffi_cif *cif,
|
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 ----------------------------------------- */
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
#define FFI_CLOSURES 1
|
#define FFI_CLOSURES 1
|
||||||
#define FFI_TRAMPOLINE_SIZE 36
|
#define FFI_TRAMPOLINE_SIZE 24
|
||||||
#define FFI_NATIVE_RAW_API 0
|
#define FFI_NATIVE_RAW_API 0
|
||||||
|
|
||||||
/* ---- Internal ---- */
|
/* ---- Internal ---- */
|
||||||
|
|
||||||
#if defined (__APPLE__)
|
#if defined (__APPLE__)
|
||||||
#define FFI_TARGET_SPECIFIC_VARIADIC
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
#define AARCH64_FFI_WITH_V_BIT 0
|
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
|
|
||||||
#define AARCH64_N_XREG 32
|
|
||||||
#define AARCH64_N_VREG 32
|
|
||||||
#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 + AARCH64_N_VREG * 16)
|
|
||||||
|
|
||||||
#endif
|
#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
|
#define LIBFFI_ASM
|
||||||
#include <fficonfig.h>
|
#include <fficonfig.h>
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
|
#include <ffi_cfi.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
#ifdef HAVE_MACHINE_ASM_H
|
#ifdef HAVE_MACHINE_ASM_H
|
||||||
#include <machine/asm.h>
|
#include <machine/asm.h>
|
||||||
@@ -37,297 +39,360 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
|
#ifdef __AARCH64EB__
|
||||||
#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
|
# define BE(X) X
|
||||||
#define cfi_restore(reg) .cfi_restore reg
|
#else
|
||||||
#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
|
# define BE(X) 0
|
||||||
|
|
||||||
.text
|
|
||||||
.globl CNAME(ffi_call_SYSV)
|
|
||||||
#ifdef __ELF__
|
|
||||||
.type CNAME(ffi_call_SYSV), #function
|
|
||||||
#endif
|
|
||||||
#ifdef __APPLE__
|
|
||||||
.align 2
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ffi_call_SYSV()
|
.text
|
||||||
|
.align 4
|
||||||
|
|
||||||
Create a stack frame, setup an argument context, call the callee
|
/* ffi_call_SYSV
|
||||||
and extract the result.
|
extern void ffi_call_SYSV (void *stack, void *frame,
|
||||||
|
void (*fn)(void), void *rvalue,
|
||||||
The maximum required argument stack size is provided,
|
int flags, void *closure);
|
||||||
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));
|
|
||||||
|
|
||||||
Therefore on entry we have:
|
Therefore on entry we have:
|
||||||
|
|
||||||
x0 prepare_fn
|
x0 stack
|
||||||
x1 &context
|
x1 frame
|
||||||
x2 &ecif
|
x2 fn
|
||||||
x3 bytes
|
x3 rvalue
|
||||||
x4 fn
|
x4 flags
|
||||||
|
x5 closure
|
||||||
|
*/
|
||||||
|
|
||||||
This function uses the following stack frame layout:
|
cfi_startproc
|
||||||
|
|
||||||
==
|
|
||||||
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
|
|
||||||
CNAME(ffi_call_SYSV):
|
CNAME(ffi_call_SYSV):
|
||||||
stp x29, x30, [sp, #-16]!
|
/* Use a stack frame allocated by our caller. */
|
||||||
cfi_adjust_cfa_offset (16)
|
cfi_def_cfa(x1, 32);
|
||||||
cfi_rel_offset (x29, 0)
|
stp x29, x30, [x1]
|
||||||
cfi_rel_offset (x30, 8)
|
mov x29, x1
|
||||||
|
mov sp, x0
|
||||||
|
cfi_def_cfa_register(x29)
|
||||||
|
cfi_rel_offset (x29, 0)
|
||||||
|
cfi_rel_offset (x30, 8)
|
||||||
|
|
||||||
mov x29, sp
|
mov x9, x2 /* save fn */
|
||||||
cfi_def_cfa_register (x29)
|
mov x8, x3 /* install structure return */
|
||||||
sub sp, sp, #ffi_call_SYSV_FS
|
#ifdef FFI_GO_CLOSURES
|
||||||
|
mov x18, x5 /* install static chain */
|
||||||
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)
|
|
||||||
#endif
|
#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
|
/* ffi_closure_SYSV
|
||||||
|
|
||||||
Closure invocation glue. This is the low level code invoked directly by
|
Closure invocation glue. This is the low level code invoked directly by
|
||||||
the closure trampoline to setup and call a closure.
|
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.
|
all other registers are preserved.
|
||||||
|
|
||||||
We allocate a call context and save the argument passing registers,
|
We allocate a call context and save the argument passing registers,
|
||||||
then invoked the generic C ffi_closure_SYSV_inner() function to do all
|
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 real work, on return we load the result passing registers back from
|
||||||
the call context.
|
the call context.
|
||||||
|
*/
|
||||||
|
|
||||||
On entry
|
#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64)
|
||||||
|
|
||||||
extern void
|
.align 4
|
||||||
ffi_closure_SYSV (struct trampoline_data *);
|
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
|
/* Save the argument passing vector registers. */
|
||||||
{
|
stp q0, q1, [sp, #16 + 0]
|
||||||
UINT64 *ffi_closure;
|
stp q2, q3, [sp, #16 + 32]
|
||||||
UINT64 flags;
|
stp q4, q5, [sp, #16 + 64]
|
||||||
};
|
stp q6, q7, [sp, #16 + 96]
|
||||||
|
b 0f
|
||||||
|
cfi_endproc
|
||||||
|
|
||||||
This function uses the following stack frame layout:
|
.globl CNAME(ffi_closure_SYSV_V)
|
||||||
|
|
||||||
==
|
|
||||||
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
|
|
||||||
#ifdef __ELF__
|
#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
|
#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 */
|
||||||
|
|||||||
+327
-94
@@ -1,6 +1,6 @@
|
|||||||
/* -----------------------------------------------------------------------
|
/* -----------------------------------------------------------------------
|
||||||
ffi.c - Copyright (c) 2012 Anthony Green
|
ffi.c - Copyright (c) 2012 Anthony Green
|
||||||
Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
|
Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
|
||||||
|
|
||||||
Alpha Foreign Function Interface
|
Alpha Foreign Function Interface
|
||||||
|
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
#include <ffi_common.h>
|
#include <ffi_common.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
||||||
all further uses in this file will refer to the 128-bit type. */
|
all further uses in this file will refer to the 128-bit type. */
|
||||||
@@ -40,135 +41,286 @@
|
|||||||
# define FFI_TYPE_LONGDOUBLE 4
|
# define FFI_TYPE_LONGDOUBLE 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void))
|
extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
|
||||||
FFI_HIDDEN;
|
void *raddr, void (*fn)(void), void *closure)
|
||||||
|
FFI_HIDDEN;
|
||||||
extern void ffi_closure_osf(void) 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)
|
ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
{
|
{
|
||||||
/* Adjust cif->bytes to represent a minimum 6 words for the temporary
|
size_t bytes = 0;
|
||||||
register argument loading area. */
|
int flags, i, avn;
|
||||||
if (cif->bytes < 6*FFI_SIZEOF_ARG)
|
ffi_type *rtype, *itype;
|
||||||
cif->bytes = 6*FFI_SIZEOF_ARG;
|
|
||||||
|
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 */
|
/* 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:
|
case FFI_TYPE_FLOAT:
|
||||||
|
flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
|
||||||
|
break;
|
||||||
case FFI_TYPE_DOUBLE:
|
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;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
/* 128-bit long double is returned in memory, like a struct. */
|
case FFI_TYPE_STRUCT:
|
||||||
cif->flags = 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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cif->flags = FFI_TYPE_INT;
|
abort();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
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;
|
return FFI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
void
|
extend_basic_type(void *valp, int type, int argn)
|
||||||
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
|
||||||
{
|
{
|
||||||
unsigned long *stack, *argp;
|
switch (type)
|
||||||
long i, avn;
|
{
|
||||||
|
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;
|
ffi_type **arg_types;
|
||||||
|
void *frame;
|
||||||
|
|
||||||
/* If the return value is a struct and we don't have a return
|
/* If the return value is a struct and we don't have a return
|
||||||
value address then we need to make one. */
|
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);
|
rvalue = alloca(cif->rtype->size);
|
||||||
|
|
||||||
/* Allocate the space for the arguments, plus 4 words of temp
|
/* Allocate the space for the arguments, plus 4 words of temp
|
||||||
space for ffi_call_osf. */
|
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)
|
argn = 0;
|
||||||
*(void **) argp++ = rvalue;
|
if (flags == ALPHA_RET_IN_MEM)
|
||||||
|
argp[argn++] = (unsigned long)rvalue;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
avn = cif->nargs;
|
avn = cif->nargs;
|
||||||
arg_types = cif->arg_types;
|
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:
|
case FFI_TYPE_SINT8:
|
||||||
*(SINT64 *) argp = *(SINT8 *)(* avalue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
case FFI_TYPE_UINT8:
|
||||||
*(SINT64 *) argp = *(UINT8 *)(* avalue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
case FFI_TYPE_SINT16:
|
||||||
*(SINT64 *) argp = *(SINT16 *)(* avalue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
case FFI_TYPE_UINT16:
|
||||||
*(SINT64 *) argp = *(UINT16 *)(* avalue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT32:
|
case FFI_TYPE_SINT32:
|
||||||
case FFI_TYPE_UINT32:
|
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_SINT64:
|
||||||
case FFI_TYPE_UINT64:
|
case FFI_TYPE_UINT64:
|
||||||
case FFI_TYPE_POINTER:
|
case FFI_TYPE_POINTER:
|
||||||
*(UINT64 *) argp = *(UINT64 *)(* avalue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
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:
|
case FFI_TYPE_DOUBLE:
|
||||||
*(double *) argp = *(double *)(* avalue);
|
argp[argn] = extend_basic_type(valp, type, argn);
|
||||||
|
argn++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
/* 128-bit long double is passed by reference. */
|
by_reference:
|
||||||
*(long double **) argp = (long double *)(* avalue);
|
/* Note that 128-bit long double is passed by reference. */
|
||||||
size = sizeof (long double *);
|
argp[argn++] = (unsigned long)valp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FFI_TYPE_VOID:
|
||||||
case FFI_TYPE_STRUCT:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
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_status
|
||||||
ffi_prep_closure_loc (ffi_closure* closure,
|
ffi_prep_closure_loc (ffi_closure* closure,
|
||||||
@@ -204,39 +356,56 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||||||
return FFI_OK;
|
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
|
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;
|
void **avalue;
|
||||||
ffi_type **arg_types;
|
ffi_type **arg_types;
|
||||||
long i, avn, argn;
|
long i, avn, argn, flags;
|
||||||
|
|
||||||
cif = closure->cif;
|
|
||||||
avalue = alloca(cif->nargs * sizeof(void *));
|
avalue = alloca(cif->nargs * sizeof(void *));
|
||||||
|
flags = cif->flags;
|
||||||
argn = 0;
|
argn = 0;
|
||||||
|
|
||||||
/* Copy the caller's structure return address to that the closure
|
/* Copy the caller's structure return address to that the closure
|
||||||
returns the data directly to the caller. */
|
returns the data directly to the caller. */
|
||||||
if (cif->flags == FFI_TYPE_STRUCT)
|
if (flags == ALPHA_RET_IN_MEM)
|
||||||
{
|
{
|
||||||
rvalue = (void *) argp[0];
|
rvalue = (void *) argp[0];
|
||||||
argn = 1;
|
argn = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
|
||||||
avn = cif->nargs;
|
|
||||||
arg_types = cif->arg_types;
|
arg_types = cif->arg_types;
|
||||||
|
|
||||||
/* Grab the addresses of the arguments from the stack frame. */
|
/* Grab the addresses of the arguments from the stack frame. */
|
||||||
while (i < avn)
|
for (i = 0, avn = cif->nargs; i < avn; i++)
|
||||||
{
|
{
|
||||||
size_t size = arg_types[i]->size;
|
ffi_type *ty = arg_types[i];
|
||||||
|
int type = ty->type;
|
||||||
|
void *valp = &argp[argn];
|
||||||
|
size_t size;
|
||||||
|
|
||||||
switch (arg_types[i]->type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
case FFI_TYPE_INT:
|
||||||
case FFI_TYPE_SINT8:
|
case FFI_TYPE_SINT8:
|
||||||
case FFI_TYPE_UINT8:
|
case FFI_TYPE_UINT8:
|
||||||
case FFI_TYPE_SINT16:
|
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_SINT64:
|
||||||
case FFI_TYPE_UINT64:
|
case FFI_TYPE_UINT64:
|
||||||
case FFI_TYPE_POINTER:
|
case FFI_TYPE_POINTER:
|
||||||
|
argn += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FFI_TYPE_VOID:
|
||||||
case FFI_TYPE_STRUCT:
|
case FFI_TYPE_STRUCT:
|
||||||
avalue[i] = &argp[argn];
|
size = ty->size;
|
||||||
|
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
|
/* Floats coming from registers need conversion from double
|
||||||
|
back to float format. */
|
||||||
if (argn < 6)
|
if (argn < 6)
|
||||||
{
|
{
|
||||||
/* Floats coming from registers need conversion from double
|
valp = &argp[argn - 6];
|
||||||
back to float format. */
|
sts(valp, argp[argn - 6]);
|
||||||
*(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
|
|
||||||
avalue[i] = &argp[argn - 6];
|
|
||||||
}
|
}
|
||||||
else
|
argn += 1;
|
||||||
avalue[i] = &argp[argn];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
|
if (argn < 6)
|
||||||
|
valp = &argp[argn - 6];
|
||||||
|
argn += 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
|
by_reference:
|
||||||
/* 128-bit long double is passed by reference. */
|
/* 128-bit long double is passed by reference. */
|
||||||
avalue[i] = (long double *) argp[argn];
|
valp = (void *)argp[argn];
|
||||||
size = sizeof (long double *);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
avalue[i] = valp;
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke the closure. */
|
/* 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. */
|
/* 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;
|
} ffi_abi;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||||
|
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
|
|
||||||
/* ---- Definitions for closures ----------------------------------------- */
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
#define FFI_CLOSURES 1
|
#define FFI_CLOSURES 1
|
||||||
|
#define FFI_GO_CLOSURES 1
|
||||||
#define FFI_TRAMPOLINE_SIZE 24
|
#define FFI_TRAMPOLINE_SIZE 24
|
||||||
#define FFI_NATIVE_RAW_API 0
|
#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))
|
||||||
+158
-263
@@ -1,5 +1,5 @@
|
|||||||
/* -----------------------------------------------------------------------
|
/* -----------------------------------------------------------------------
|
||||||
osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011 Red Hat
|
osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011, 2014 Red Hat
|
||||||
|
|
||||||
Alpha/OSF Foreign Function Interface
|
Alpha/OSF Foreign Function Interface
|
||||||
|
|
||||||
@@ -27,37 +27,46 @@
|
|||||||
#define LIBFFI_ASM
|
#define LIBFFI_ASM
|
||||||
#include <fficonfig.h>
|
#include <fficonfig.h>
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
|
#include <ffi_cfi.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
.arch ev6
|
.arch ev6
|
||||||
.text
|
.text
|
||||||
|
|
||||||
/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
|
/* Aid in building a direct addressed jump table, 4 insns per entry. */
|
||||||
void *raddr, void (*fnaddr)(void));
|
.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
|
for this function. This has been allocated by ffi_call. We also
|
||||||
deallocate some of the stack that has been alloca'd. */
|
deallocate some of the stack that has been alloca'd. */
|
||||||
|
|
||||||
.align 3
|
.align 4
|
||||||
.globl ffi_call_osf
|
.globl ffi_call_osf
|
||||||
.ent ffi_call_osf
|
.ent ffi_call_osf
|
||||||
FFI_HIDDEN(ffi_call_osf)
|
FFI_HIDDEN(ffi_call_osf)
|
||||||
|
|
||||||
ffi_call_osf:
|
ffi_call_osf:
|
||||||
.frame $15, 32, $26, 0
|
cfi_startproc
|
||||||
.mask 0x4008000, -32
|
cfi_def_cfa($17, 32)
|
||||||
$LFB1:
|
|
||||||
addq $16,$17,$1
|
|
||||||
mov $16, $30
|
mov $16, $30
|
||||||
stq $26, 0($1)
|
stq $26, 0($17)
|
||||||
stq $15, 8($1)
|
stq $15, 8($17)
|
||||||
stq $18, 16($1)
|
mov $17, $15
|
||||||
mov $1, $15
|
|
||||||
$LCFI1:
|
|
||||||
.prologue 0
|
.prologue 0
|
||||||
|
cfi_def_cfa_register($15)
|
||||||
|
cfi_rel_offset($26, 0)
|
||||||
|
cfi_rel_offset($15, 8)
|
||||||
|
|
||||||
stq $19, 24($1)
|
stq $18, 16($17) # save flags into frame
|
||||||
mov $20, $27
|
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.
|
# Load up all of the (potential) argument registers.
|
||||||
ldq $16, 0($30)
|
ldq $16, 0($30)
|
||||||
@@ -77,310 +86,196 @@ $LCFI1:
|
|||||||
lda $30, 48($30)
|
lda $30, 48($30)
|
||||||
|
|
||||||
jsr $26, ($27), 0
|
jsr $26, ($27), 0
|
||||||
ldgp $29, 0($26)
|
0:
|
||||||
|
ldah $29, 0($26) !gpdisp!1
|
||||||
# If the return value pointer is NULL, assume no return value.
|
ldq $2, 24($15) # reload rvalue
|
||||||
ldq $19, 24($15)
|
lda $29, 0($29) !gpdisp!1
|
||||||
ldq $18, 16($15)
|
ldq $3, 16($15) # reload flags
|
||||||
|
lda $1, 99f-0b($26)
|
||||||
ldq $26, 0($15)
|
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)
|
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
|
.align 4
|
||||||
$retint:
|
99:
|
||||||
stq $0, 0($19)
|
E ALPHA_ST_VOID
|
||||||
nop
|
ret
|
||||||
ldq $15, 8($15)
|
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
|
ret
|
||||||
|
|
||||||
.align 4
|
cfi_endproc
|
||||||
$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:
|
|
||||||
|
|
||||||
.end ffi_call_osf
|
.end ffi_call_osf
|
||||||
|
|
||||||
/* ffi_closure_osf(...)
|
/* ffi_closure_osf(...)
|
||||||
|
|
||||||
Receives the closure argument in $1. */
|
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
|
.globl ffi_closure_osf
|
||||||
.ent ffi_closure_osf
|
.ent ffi_closure_osf
|
||||||
FFI_HIDDEN(ffi_closure_osf)
|
FFI_HIDDEN(ffi_closure_osf)
|
||||||
|
|
||||||
ffi_closure_osf:
|
ffi_closure_osf:
|
||||||
.frame $30, 16*8, $26, 0
|
cfi_startproc
|
||||||
.mask 0x4000000, -16*8
|
|
||||||
$LFB2:
|
|
||||||
ldgp $29, 0($27)
|
ldgp $29, 0($27)
|
||||||
subq $30, 16*8, $30
|
subq $30, CLOSURE_FS, $30
|
||||||
$LCFI5:
|
cfi_adjust_cfa_offset(CLOSURE_FS)
|
||||||
stq $26, 0($30)
|
stq $26, 0($30)
|
||||||
$LCFI6:
|
|
||||||
.prologue 1
|
.prologue 1
|
||||||
|
cfi_rel_offset($26, 0)
|
||||||
|
|
||||||
# Store all of the potential argument registers in va_list format.
|
# 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 $f16, 4*8($30)
|
||||||
stt $f17, 5*8($30)
|
stt $f17, 5*8($30)
|
||||||
stt $f18, 6*8($30)
|
stt $f18, 6*8($30)
|
||||||
stt $f19, 7*8($30)
|
stt $f19, 7*8($30)
|
||||||
stt $f20, 8*8($30)
|
stt $f20, 8*8($30)
|
||||||
stt $f21, 9*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.
|
# Call ffi_closure_osf_inner to do the bulk of the work.
|
||||||
mov $1, $16
|
lda $19, 2*8($30)
|
||||||
lda $17, 2*8($30)
|
lda $20, 10*8($30)
|
||||||
lda $18, 10*8($30)
|
|
||||||
jsr $26, ffi_closure_osf_inner
|
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)
|
ldq $26, 0($30)
|
||||||
|
cfi_restore($26)
|
||||||
# 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
|
|
||||||
jmp $31, ($1), $load_32
|
jmp $31, ($1), $load_32
|
||||||
|
|
||||||
.align 4
|
.macro epilogue
|
||||||
$load_none:
|
addq $30, CLOSURE_FS, $30
|
||||||
addq $30, 16*8, $30
|
cfi_adjust_cfa_offset(-CLOSURE_FS)
|
||||||
ret
|
ret
|
||||||
|
.align 4
|
||||||
|
cfi_adjust_cfa_offset(CLOSURE_FS)
|
||||||
|
.endm
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
$load_float:
|
99:
|
||||||
lds $f0, 16($30)
|
E ALPHA_LD_VOID
|
||||||
nop
|
epilogue
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
E ALPHA_LD_INT64
|
||||||
$load_double:
|
epilogue
|
||||||
ldt $f0, 16($30)
|
|
||||||
nop
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
E ALPHA_LD_INT32
|
||||||
$load_u8:
|
$load_32:
|
||||||
#ifdef __alpha_bwx__
|
sextl $0, $0
|
||||||
ldbu $0, 16($30)
|
epilogue
|
||||||
nop
|
|
||||||
#else
|
|
||||||
ldq $0, 16($30)
|
|
||||||
and $0, 255, $0
|
|
||||||
#endif
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
E ALPHA_LD_UINT16
|
||||||
$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)
|
|
||||||
zapnot $0, 3, $0
|
zapnot $0, 3, $0
|
||||||
#endif
|
epilogue
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
E ALPHA_LD_SINT16
|
||||||
$load_s16:
|
|
||||||
#ifdef __alpha_bwx__
|
#ifdef __alpha_bwx__
|
||||||
ldwu $0, 16($30)
|
|
||||||
sextw $0, $0
|
sextw $0, $0
|
||||||
#else
|
#else
|
||||||
ldq $0, 16($30)
|
|
||||||
sll $0, 48, $0
|
sll $0, 48, $0
|
||||||
sra $0, 48, $0
|
sra $0, 48, $0
|
||||||
#endif
|
#endif
|
||||||
addq $30, 16*8, $30
|
epilogue
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
E ALPHA_LD_UINT8
|
||||||
$load_32:
|
and $0, 0xff, $0
|
||||||
ldl $0, 16($30)
|
epilogue
|
||||||
nop
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
E ALPHA_LD_SINT8
|
||||||
$load_64:
|
#ifdef __alpha_bwx__
|
||||||
ldq $0, 16($30)
|
sextb $0, $0
|
||||||
nop
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
$LFE2:
|
|
||||||
|
|
||||||
.end ffi_closure_osf
|
|
||||||
|
|
||||||
#ifdef __ELF__
|
|
||||||
.section .rodata
|
|
||||||
#else
|
#else
|
||||||
.rdata
|
sll $0, 56, $0
|
||||||
|
sra $0, 56, $0
|
||||||
#endif
|
#endif
|
||||||
$load_table:
|
epilogue
|
||||||
.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
|
|
||||||
|
|
||||||
/* 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 \
|
E ALPHA_LD_DOUBLE
|
||||||
|| FFI_TYPE_DOUBLE != 3 \
|
ldt $f0, 16($sp)
|
||||||
|| FFI_TYPE_UINT8 != 5 \
|
epilogue
|
||||||
|| 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
|
|
||||||
|
|
||||||
#ifdef __ELF__
|
E ALPHA_LD_CPLXF
|
||||||
# define UA_SI .4byte
|
lds $f0, 16($sp)
|
||||||
# define FDE_ENCODING 0x1b /* pcrel sdata4 */
|
lds $f1, 20($sp)
|
||||||
# define FDE_ENCODE(X) .4byte X-.
|
epilogue
|
||||||
# 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
|
|
||||||
|
|
||||||
#ifdef __ELF__
|
E ALPHA_LD_CPLXD
|
||||||
.section .eh_frame,EH_FRAME_FLAGS,@progbits
|
ldt $f0, 16($sp)
|
||||||
#elif defined __osf__
|
ldt $f1, 24($sp)
|
||||||
.data
|
epilogue
|
||||||
.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
|
|
||||||
|
|
||||||
.byte 0x4 # DW_CFA_advance_loc4
|
cfi_endproc
|
||||||
UA_SI $LCFI1-$LFB1
|
.end ffi_closure_osf
|
||||||
.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
|
|
||||||
|
|
||||||
#if defined __ELF__ && defined __linux__
|
#if defined __ELF__ && defined __linux__
|
||||||
.section .note.GNU-stack,"",@progbits
|
.section .note.GNU-stack,"",@progbits
|
||||||
|
|||||||
+690
-578
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 \
|
#define FFI_EXTRA_CIF_FIELDS \
|
||||||
int vfp_used; \
|
int vfp_used; \
|
||||||
short vfp_reg_free, vfp_nargs; \
|
unsigned short vfp_reg_free, vfp_nargs; \
|
||||||
signed char vfp_args[16] \
|
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_SPECIFIC_VARIADIC
|
||||||
|
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
|
|
||||||
/* ---- Definitions for closures ----------------------------------------- */
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
#define FFI_CLOSURES 1
|
#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
|
#define FFI_NATIVE_RAW_API 0
|
||||||
|
|
||||||
#endif
|
#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
@@ -28,463 +28,307 @@
|
|||||||
#define LIBFFI_ASM
|
#define LIBFFI_ASM
|
||||||
#include <fficonfig.h>
|
#include <fficonfig.h>
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
#ifdef HAVE_MACHINE_ASM_H
|
#include <ffi_cfi.h>
|
||||||
#include <machine/asm.h>
|
#include "internal.h"
|
||||||
#else
|
|
||||||
#ifdef __USER_LABEL_PREFIX__
|
|
||||||
#define CONCAT1(a, b) CONCAT2(a, b)
|
|
||||||
#define CONCAT2(a, b) a ## b
|
|
||||||
|
|
||||||
/* Use the right prefix for global labels. */
|
/* GCC 4.8 provides __ARM_ARCH; construct it otherwise. */
|
||||||
#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
|
#ifndef __ARM_ARCH
|
||||||
#else
|
# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|
||||||
#define CNAME(x) x
|
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|
||||||
#endif
|
|| defined(__ARM_ARCH_7EM__)
|
||||||
#ifdef __APPLE__
|
# define __ARM_ARCH 7
|
||||||
#define ENTRY(x) .globl _##x; _##x:
|
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||||
#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__) \
|
|
||||||
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|
||||||
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
|
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
|
||||||
|| defined(__ARM_ARCH_6M__)
|
|| defined(__ARM_ARCH_6M__)
|
||||||
# undef __ARM_ARCH__
|
# define __ARM_ARCH 6
|
||||||
# define __ARM_ARCH__ 6
|
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|
||||||
#endif
|
|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|
||||||
|
|| defined(__ARM_ARCH_5TEJ__)
|
||||||
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|
# define __ARM_ARCH 5
|
||||||
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|
# else
|
||||||
|| defined(__ARM_ARCH_7EM__)
|
# define __ARM_ARCH 4
|
||||||
# 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__
|
|
||||||
# endif
|
# endif
|
||||||
#else
|
|
||||||
# define call_reg(x) mov lr, pc ; mov pc, x
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Conditionally compile unwinder directives. */
|
/* Conditionally compile unwinder directives. */
|
||||||
|
.macro UNWIND text:vararg
|
||||||
#ifdef __ARM_EABI__
|
#ifdef __ARM_EABI__
|
||||||
#define UNWIND
|
\text
|
||||||
#else
|
|
||||||
#define UNWIND @
|
|
||||||
#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
|
|
||||||
#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
|
|
||||||
#else
|
|
||||||
.ifc "\regs",""
|
|
||||||
ldr\cond pc, [sp], #4
|
|
||||||
.else
|
|
||||||
ldm\cond\dirn sp!, {\regs, pc}
|
|
||||||
.endif
|
|
||||||
#endif
|
#endif
|
||||||
.endm
|
.endm
|
||||||
|
#if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
|
||||||
|
.cfi_sections .debug_frame
|
||||||
|
#endif
|
||||||
|
|
||||||
@ r0: ffi_prep_args
|
#define CONCAT(a, b) CONCAT2(a, b)
|
||||||
@ r1: &ecif
|
#define CONCAT2(a, b) a ## b
|
||||||
@ r2: cif->bytes
|
|
||||||
@ r3: fig->flags
|
|
||||||
@ sp+0: ecif.rvalue
|
|
||||||
|
|
||||||
@ This assumes we are using gas.
|
#ifdef __USER_LABEL_PREFIX__
|
||||||
ARM_FUNC_START(ffi_call_SYSV)
|
# define CNAME(X) CONCAT (__USER_LABEL_PREFIX__, X)
|
||||||
@ Save registers
|
#else
|
||||||
stmfd sp!, {r0-r3, fp, lr}
|
# define CNAME(X) X
|
||||||
UNWIND .save {r0-r3, fp, lr}
|
#endif
|
||||||
mov fp, sp
|
#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
|
||||||
|
|
||||||
UNWIND .setfp fp, sp
|
#define ARM_FUNC_START(name, gl) \
|
||||||
|
.align 3; \
|
||||||
|
.ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \
|
||||||
|
TYPE(name, %function); \
|
||||||
|
CNAME(name):
|
||||||
|
|
||||||
@ Make room for all of the new args.
|
#define ARM_FUNC_END(name) \
|
||||||
sub sp, fp, r2
|
SIZE(name)
|
||||||
|
|
||||||
@ Place all of the ffi_prep_args in position
|
/* Aid in defining a jump table with 8 bytes between entries. */
|
||||||
mov r0, sp
|
.macro E index
|
||||||
@ r1 already set
|
.if . - 0b - 8*\index
|
||||||
|
.error "type table out of sync"
|
||||||
|
.endif
|
||||||
|
.endm
|
||||||
|
|
||||||
@ Call ffi_prep_args(stack, &ecif)
|
.text
|
||||||
bl CNAME(ffi_prep_args_SYSV)
|
.syntax unified
|
||||||
|
.arm
|
||||||
|
|
||||||
@ move first 4 parameters in registers
|
/* We require interworking on LDM, which implies ARMv5T,
|
||||||
ldmia sp, {r0-r3}
|
which implies the existance of BLX. */
|
||||||
|
.arch armv5t
|
||||||
|
|
||||||
@ and adjust stack
|
/* Note that we use STC and LDC to encode VFP instructions,
|
||||||
sub lr, fp, sp @ cif->bytes == fp - sp
|
so that we do not need ".fpu vfp", nor get that added to
|
||||||
ldr ip, [fp] @ load fn() in advance
|
the object file attributes. These will not be executed
|
||||||
cmp lr, #16
|
unless the FFI_VFP abi is used. */
|
||||||
movhs lr, #16
|
|
||||||
add sp, sp, lr
|
|
||||||
|
|
||||||
@ call (fn) (...)
|
@ r0: stack
|
||||||
call_reg(ip)
|
@ r1: frame
|
||||||
|
@ r2: fn
|
||||||
|
@ r3: vfp_used
|
||||||
|
|
||||||
@ Remove the space we pushed for the args
|
ARM_FUNC_START(ffi_call_VFP, 1)
|
||||||
mov sp, fp
|
UNWIND .fnstart
|
||||||
|
cfi_startproc
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
ARM_FUNC_START(ffi_call_SYSV, 1)
|
||||||
|
stm r1, {fp, lr}
|
||||||
|
mov fp, r1
|
||||||
|
|
||||||
|
@ This is a bit of a lie wrt the origin of the unwind info, but
|
||||||
|
@ now we've got the usual frame pointer and two saved registers.
|
||||||
|
UNWIND .save {fp,lr}
|
||||||
|
UNWIND .setfp fp, sp
|
||||||
|
cfi_def_cfa(fp, 8)
|
||||||
|
cfi_rel_offset(fp, 0)
|
||||||
|
cfi_rel_offset(lr, 4)
|
||||||
|
|
||||||
|
mov sp, r0 @ install the stack pointer
|
||||||
|
mov lr, r2 @ move the fn pointer out of the way
|
||||||
|
ldr ip, [fp, #16] @ install the static chain
|
||||||
|
ldmia sp!, {r0-r3} @ move first 4 parameters in registers.
|
||||||
|
blx lr @ call fn
|
||||||
|
|
||||||
@ Load r2 with the pointer to storage for the return value
|
@ Load r2 with the pointer to storage for the return value
|
||||||
ldr r2, [sp, #24]
|
|
||||||
|
|
||||||
@ Load r3 with the return type code
|
@ Load r3 with the return type code
|
||||||
ldr r3, [sp, #12]
|
ldr r2, [fp, #8]
|
||||||
|
ldr r3, [fp, #12]
|
||||||
|
|
||||||
@ If the return value pointer is NULL, assume no return value.
|
@ Deallocate the stack with the arguments.
|
||||||
cmp r2, #0
|
mov sp, fp
|
||||||
beq LSYM(Lepilogue)
|
cfi_def_cfa_register(sp)
|
||||||
|
|
||||||
@ return INT
|
@ Store values stored in registers.
|
||||||
cmp r3, #FFI_TYPE_INT
|
.align 3
|
||||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
add pc, pc, r3, lsl #3
|
||||||
cmpne r3, #FFI_TYPE_FLOAT
|
nop
|
||||||
#endif
|
0:
|
||||||
streq r0, [r2]
|
E ARM_TYPE_VFP_S
|
||||||
beq LSYM(Lepilogue)
|
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 INT64
|
cfi_endproc
|
||||||
cmp r3, #FFI_TYPE_SINT64
|
UNWIND .fnend
|
||||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
ARM_FUNC_END(ffi_call_SYSV)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
unsigned int FFI_HIDDEN
|
int ffi_closure_inner_* (cif, fun, user_data, frame)
|
||||||
ffi_closure_inner (closure, respp, args)
|
|
||||||
ffi_closure *closure;
|
|
||||||
void **respp;
|
|
||||||
void *args;
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ARM_FUNC_START(ffi_closure_SYSV)
|
ARM_FUNC_START(ffi_go_closure_SYSV, 1)
|
||||||
UNWIND .pad #16
|
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
|
add ip, sp, #16
|
||||||
stmfd sp!, {ip, lr}
|
sub sp, sp, #64+32 @ allocate frame
|
||||||
UNWIND .save {r0, lr}
|
cfi_adjust_cfa_offset(64+32)
|
||||||
add r2, sp, #8
|
stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7}
|
||||||
UNWIND .pad #16
|
stmdb sp!, {ip,lr}
|
||||||
sub sp, sp, #16
|
|
||||||
str sp, [sp, #8]
|
/* See above. */
|
||||||
add r1, sp, #8
|
UNWIND .save {sp,lr}
|
||||||
bl CNAME(ffi_closure_inner)
|
cfi_adjust_cfa_offset(8)
|
||||||
cmp r0, #FFI_TYPE_INT
|
cfi_rel_offset(lr, 4)
|
||||||
beq .Lretint
|
|
||||||
|
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
|
#else
|
||||||
beq .Lretfloat
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cmp r0, #FFI_TYPE_DOUBLE
|
ARM_FUNC_START(ffi_arm_trampoline, 1)
|
||||||
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
|
0: adr ip, 0b
|
||||||
beq .Lretlonglong
|
ldr pc, 1f
|
||||||
#else
|
1: .long 0
|
||||||
beq .Lretdouble
|
ARM_FUNC_END(ffi_arm_trampoline)
|
||||||
#endif
|
|
||||||
|
|
||||||
cmp r0, #FFI_TYPE_LONGDOUBLE
|
#endif /* FFI_EXEC_TRAMPOLINE_TABLE */
|
||||||
#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]
|
|
||||||
|
|
||||||
#if defined __ELF__ && defined __linux__
|
#if defined __ELF__ && defined __linux__
|
||||||
.section .note.GNU-stack,"",%progbits
|
.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
|
#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||||
/* Make space for the return structure pointer */
|
/* Make space for the return structure pointer */
|
||||||
if (cif->rtype->type == FFI_TYPE_STRUCT
|
if (cif->rtype->type == FFI_TYPE_STRUCT
|
||||||
#ifdef SPARC
|
|
||||||
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
|
|
||||||
#endif
|
|
||||||
#ifdef TILE
|
#ifdef TILE
|
||||||
&& (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
|
&& (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
|
||||||
#endif
|
#endif
|
||||||
@@ -179,14 +176,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|||||||
FFI_ASSERT_VALID_TYPE(*ptr);
|
FFI_ASSERT_VALID_TYPE(*ptr);
|
||||||
|
|
||||||
#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
#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 */
|
/* Add any padding if necessary */
|
||||||
if (((*ptr)->alignment - 1) & bytes)
|
if (((*ptr)->alignment - 1) & bytes)
|
||||||
|
|||||||
+342
-555
@@ -27,655 +27,442 @@
|
|||||||
|
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
#include <ffi_common.h>
|
#include <ffi_common.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#ifndef SPARC64
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space
|
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
||||||
has been allocated for the function's arguments */
|
all further uses in this file will refer to the 128-bit type. */
|
||||||
|
|
||||||
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
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
#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
|
#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 */
|
/* 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;
|
ffi_type *rtype = cif->rtype;
|
||||||
|
int rtt = rtype->type;
|
||||||
if (cif->abi != FFI_V9)
|
size_t bytes;
|
||||||
{
|
int i, n, flags;
|
||||||
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);
|
|
||||||
|
|
||||||
/* Set the return type flag */
|
/* Set the return type flag */
|
||||||
switch (cif->rtype->type)
|
switch (rtt)
|
||||||
{
|
{
|
||||||
case FFI_TYPE_VOID:
|
case FFI_TYPE_VOID:
|
||||||
|
flags = SPARC_RET_VOID;
|
||||||
|
break;
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
|
flags = SPARC_RET_F_1;
|
||||||
|
break;
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
flags = SPARC_RET_F_2;
|
||||||
|
break;
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
#endif
|
|
||||||
cif->flags = cif->rtype->type;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
case FFI_TYPE_STRUCT:
|
||||||
if (cif->abi == FFI_V9 && cif->rtype->size > 32)
|
flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
|
||||||
cif->flags = FFI_TYPE_VOID;
|
flags |= SPARC_RET_STRUCT;
|
||||||
else
|
|
||||||
cif->flags = FFI_TYPE_STRUCT;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_SINT8:
|
case FFI_TYPE_SINT8:
|
||||||
|
flags = SPARC_RET_SINT8;
|
||||||
|
break;
|
||||||
case FFI_TYPE_UINT8:
|
case FFI_TYPE_UINT8:
|
||||||
|
flags = SPARC_RET_UINT8;
|
||||||
|
break;
|
||||||
case FFI_TYPE_SINT16:
|
case FFI_TYPE_SINT16:
|
||||||
|
flags = SPARC_RET_SINT16;
|
||||||
|
break;
|
||||||
case FFI_TYPE_UINT16:
|
case FFI_TYPE_UINT16:
|
||||||
if (cif->abi == FFI_V9)
|
flags = SPARC_RET_UINT16;
|
||||||
cif->flags = FFI_TYPE_INT;
|
break;
|
||||||
else
|
case FFI_TYPE_INT:
|
||||||
cif->flags = cif->rtype->type;
|
case FFI_TYPE_SINT32:
|
||||||
|
case FFI_TYPE_UINT32:
|
||||||
|
case FFI_TYPE_POINTER:
|
||||||
|
flags = SPARC_RET_UINT32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_SINT64:
|
case FFI_TYPE_SINT64:
|
||||||
case FFI_TYPE_UINT64:
|
case FFI_TYPE_UINT64:
|
||||||
if (cif->abi == FFI_V9)
|
flags = SPARC_RET_INT64;
|
||||||
cif->flags = FFI_TYPE_INT;
|
break;
|
||||||
else
|
case FFI_TYPE_COMPLEX:
|
||||||
cif->flags = FFI_TYPE_SINT64;
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cif->flags = FFI_TYPE_INT;
|
abort();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
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;
|
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))
|
if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
|
||||||
off = ALIGN(off, (*ptr)->alignment);
|
|
||||||
|
|
||||||
switch ((*ptr)->type)
|
|
||||||
{
|
{
|
||||||
case FFI_TYPE_STRUCT:
|
/* Since we pass the pointer to the callee, we need a value.
|
||||||
off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
|
We allowed for this space in ffi_call, before ffi_call_v8
|
||||||
off = ALIGN(off, FFI_SIZEOF_ARG);
|
alloca'd the space. */
|
||||||
break;
|
rvalue = (char *)argp + cif->bytes;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
rval = NULL;
|
/* Otherwise, we can ignore the return value. */
|
||||||
if (rvalue == NULL)
|
flags = SPARC_RET_VOID;
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
ffi_type *ty = p_arg[i];
|
||||||
#ifdef SPARC64
|
void *a = avalue[i];
|
||||||
/* We don't yet support calling 32bit code from 64bit */
|
int tt = ty->type;
|
||||||
FFI_ASSERT(0);
|
size_t z;
|
||||||
#else
|
|
||||||
if (rvalue && (cif->rtype->type == FFI_TYPE_STRUCT
|
switch (tt)
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
|| cif->flags == FFI_TYPE_LONGDOUBLE
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
{
|
{
|
||||||
/* For v8, we need an "unimp" with size of returning struct */
|
case FFI_TYPE_STRUCT:
|
||||||
/* behind "call", so we alloc some executable space for it. */
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
/* l7 is used, we need to make sure v8.S doesn't use %l7. */
|
by_reference:
|
||||||
unsigned int *call_struct = NULL;
|
*argp++ = (unsigned long)a;
|
||||||
ffi_closure_alloc(32, (void **)&call_struct);
|
break;
|
||||||
if (call_struct)
|
|
||||||
|
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;
|
memcpy((char *)argp + 4 - z, a, z);
|
||||||
call_struct[0] = 0xae10001f; /* mov %i7, %l7 */
|
argp++;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
|
memcpy(argp, a, z);
|
||||||
cif->flags, rvalue, fn);
|
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
|
FFI_ASSERT (cif->abi == FFI_V8);
|
||||||
extern void ffi_closure_v9(void);
|
|
||||||
|
/* 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
|
#else
|
||||||
extern void ffi_closure_v8(void);
|
extern void ffi_flush_icache (void *) FFI_HIDDEN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern void ffi_closure_v8(void) FFI_HIDDEN;
|
||||||
|
extern void ffi_go_closure_v8(void) FFI_HIDDEN;
|
||||||
|
|
||||||
ffi_status
|
ffi_status
|
||||||
ffi_prep_closure_loc (ffi_closure* closure,
|
ffi_prep_closure_loc (ffi_closure *closure,
|
||||||
ffi_cif* cif,
|
ffi_cif *cif,
|
||||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||||
void *user_data,
|
void *user_data,
|
||||||
void *codeloc)
|
void *codeloc)
|
||||||
{
|
{
|
||||||
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
|
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
|
||||||
unsigned long fn;
|
unsigned long ctx = (unsigned long) closure;
|
||||||
#ifdef SPARC64
|
unsigned long fn = (unsigned long) ffi_closure_v8;
|
||||||
/* 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;
|
|
||||||
if (cif->abi != FFI_V8)
|
if (cif->abi != FFI_V8)
|
||||||
return FFI_BAD_ABI;
|
return FFI_BAD_ABI;
|
||||||
fn = (unsigned long) ffi_closure_v8;
|
|
||||||
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
|
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
|
||||||
tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
|
tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
|
||||||
tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
|
tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
|
||||||
tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
|
tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
|
||||||
#endif
|
|
||||||
|
|
||||||
closure->cif = cif;
|
closure->cif = cif;
|
||||||
closure->fun = fun;
|
closure->fun = fun;
|
||||||
closure->user_data = user_data;
|
closure->user_data = user_data;
|
||||||
|
|
||||||
/* Flush the Icache. closure is 8 bytes aligned. */
|
ffi_flush_icache (closure);
|
||||||
#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
|
|
||||||
|
|
||||||
return FFI_OK;
|
return FFI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
ffi_status
|
||||||
ffi_closure_sparc_inner_v8(ffi_closure *closure,
|
ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
|
||||||
void *rvalue, unsigned long *gpr, unsigned long *scratch)
|
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;
|
ffi_type **arg_types;
|
||||||
void **avalue;
|
void **avalue;
|
||||||
int i, argn;
|
int i, nargs, flags;
|
||||||
|
|
||||||
cif = closure->cif;
|
|
||||||
arg_types = cif->arg_types;
|
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
|
/* Copy the caller's structure return address so that the closure
|
||||||
returns the data directly to the caller. */
|
returns the data directly to the caller. Also install it so we
|
||||||
if (cif->flags == FFI_TYPE_STRUCT
|
can return the address in %o0. */
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
|
||||||
|| cif->flags == FFI_TYPE_LONGDOUBLE
|
{
|
||||||
#endif
|
void *new_rvalue = (void *)*argp;
|
||||||
)
|
*(void **)rvalue = new_rvalue;
|
||||||
rvalue = (void *) gpr[0];
|
rvalue = new_rvalue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Always skip the structure return address. */
|
/* Always skip the structure return address. */
|
||||||
argn = 1;
|
argp++;
|
||||||
|
|
||||||
/* Grab the addresses of the arguments from the stack frame. */
|
/* 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
|
ffi_type *ty = arg_types[i];
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
int tt = ty->type;
|
||||||
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE
|
void *a = argp;
|
||||||
#endif
|
size_t z;
|
||||||
)
|
|
||||||
|
switch (tt)
|
||||||
{
|
{
|
||||||
|
case FFI_TYPE_STRUCT:
|
||||||
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
|
by_reference:
|
||||||
/* Straight copy of invisible reference. */
|
/* Straight copy of invisible reference. */
|
||||||
avalue[i] = (void *)gpr[argn++];
|
a = (void *)*argp;
|
||||||
}
|
break;
|
||||||
else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
|
|
||||||
|| arg_types[i]->type == FFI_TYPE_SINT64
|
case FFI_TYPE_DOUBLE:
|
||||||
|| arg_types[i]->type == FFI_TYPE_UINT64)
|
case FFI_TYPE_SINT64:
|
||||||
/* gpr is 8-byte aligned. */
|
case FFI_TYPE_UINT64:
|
||||||
&& (argn % 2) != 0)
|
if ((unsigned long)a & 7)
|
||||||
{
|
{
|
||||||
/* Align on a 8-byte boundary. */
|
/* Align on a 8-byte boundary. */
|
||||||
scratch[0] = gpr[argn];
|
UINT64 *tmp = alloca(8);
|
||||||
scratch[1] = gpr[argn+1];
|
*tmp = ((UINT64)argp[0] << 32) | argp[1];
|
||||||
avalue[i] = scratch;
|
a = tmp;
|
||||||
scratch -= 2;
|
}
|
||||||
argn += 2;
|
argp++;
|
||||||
}
|
break;
|
||||||
else
|
|
||||||
{
|
case FFI_TYPE_INT:
|
||||||
/* Always right-justify. */
|
case FFI_TYPE_FLOAT:
|
||||||
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
case FFI_TYPE_UINT32:
|
||||||
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
|
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. */
|
/* 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. */
|
/* Tell ffi_closure_sparc how to perform return type promotions. */
|
||||||
return cif->rtype->type;
|
return flags;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
#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 {
|
typedef enum ffi_abi {
|
||||||
FFI_FIRST_ABI = 0,
|
FFI_FIRST_ABI = 0,
|
||||||
FFI_V8,
|
|
||||||
FFI_V8PLUS,
|
|
||||||
FFI_V9,
|
|
||||||
FFI_LAST_ABI,
|
|
||||||
#ifdef SPARC64
|
#ifdef SPARC64
|
||||||
FFI_DEFAULT_ABI = FFI_V9
|
FFI_V9,
|
||||||
|
FFI_DEFAULT_ABI = FFI_V9,
|
||||||
#else
|
#else
|
||||||
FFI_DEFAULT_ABI = FFI_V8
|
FFI_V8,
|
||||||
|
FFI_DEFAULT_ABI = FFI_V8,
|
||||||
#endif
|
#endif
|
||||||
|
FFI_LAST_ABI
|
||||||
} ffi_abi;
|
} ffi_abi;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||||
|
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
|
|
||||||
/* ---- Definitions for closures ----------------------------------------- */
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
#define FFI_CLOSURES 1
|
#define FFI_CLOSURES 1
|
||||||
|
#define FFI_GO_CLOSURES 1
|
||||||
#define FFI_NATIVE_RAW_API 0
|
#define FFI_NATIVE_RAW_API 0
|
||||||
|
|
||||||
#ifdef SPARC64
|
#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
|
||||||
+273
-258
@@ -28,176 +28,240 @@
|
|||||||
#define LIBFFI_ASM
|
#define LIBFFI_ASM
|
||||||
#include <fficonfig.h>
|
#include <fficonfig.h>
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
|
#include <ffi_cfi.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
#define STACKFRAME 96 /* Minimum stack framesize for SPARC */
|
#ifndef SPARC64
|
||||||
#define ARGS (64+4) /* Offset of register area in frame */
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
.text
|
|
||||||
.align 8
|
.align 8
|
||||||
.globl ffi_flush_icache
|
.globl C(ffi_flush_icache)
|
||||||
.globl _ffi_flush_icache
|
.type C(ffi_flush_icache),@function
|
||||||
|
FFI_HIDDEN(C(ffi_flush_icache))
|
||||||
|
|
||||||
ffi_flush_icache:
|
C(ffi_flush_icache):
|
||||||
_ffi_flush_icache:
|
cfi_startproc
|
||||||
add %o0, %o1, %o2
|
|
||||||
#ifdef SPARC64
|
|
||||||
1: flush %o0
|
|
||||||
#else
|
|
||||||
1: iflush %o0
|
1: iflush %o0
|
||||||
#endif
|
iflush %o+8
|
||||||
add %o0, 8, %o0
|
|
||||||
cmp %o0, %o2
|
|
||||||
blt 1b
|
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
retl
|
retl
|
||||||
nop
|
nop
|
||||||
.ffi_flush_icache_end:
|
cfi_endproc
|
||||||
.size ffi_flush_icache,.ffi_flush_icache_end-ffi_flush_icache
|
.size C(ffi_flush_icache), . - C(ffi_flush_icache)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.text
|
.macro E index
|
||||||
|
.align 16
|
||||||
|
.org 2b + \index * 16
|
||||||
|
.endm
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.globl ffi_call_v8
|
.globl C(ffi_call_v8)
|
||||||
.globl _ffi_call_v8
|
.type C(ffi_call_v8),@function
|
||||||
|
FFI_HIDDEN(C(ffi_call_v8))
|
||||||
|
|
||||||
ffi_call_v8:
|
C(ffi_call_v8):
|
||||||
_ffi_call_v8:
|
cfi_startproc
|
||||||
.LLFB1:
|
! Allocate a stack frame sized by ffi_call.
|
||||||
save %sp, -STACKFRAME, %sp
|
save %sp, %o4, %sp
|
||||||
.LLCFI0:
|
cfi_def_cfa_register(%fp)
|
||||||
|
cfi_window_save
|
||||||
|
|
||||||
sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
|
mov %i0, %o0 ! copy cif
|
||||||
add %sp, STACKFRAME, %l0 ! %l0 has start of
|
add %sp, 64+32, %o1 ! load args area
|
||||||
! frame to set up
|
mov %i2, %o2 ! copy rvalue
|
||||||
|
call C(ffi_prep_args_v8)
|
||||||
|
mov %i3, %o3 ! copy avalue
|
||||||
|
|
||||||
mov %l0, %o0 ! call routine to set up frame
|
add %sp, 32, %sp ! deallocate prep frame
|
||||||
call %i0
|
and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type
|
||||||
mov %i1, %o1 ! (delay)
|
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
|
||||||
|
|
||||||
ld [%l0+ARGS], %o0 ! call foreign function
|
! Call foreign function
|
||||||
ld [%l0+ARGS+4], %o1
|
call %i1
|
||||||
ld [%l0+ARGS+8], %o2
|
mov %i5, %g2 ! load static chain
|
||||||
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
|
|
||||||
|
|
||||||
! If the return value pointer is NULL, assume no return value.
|
0: call 1f ! load pc in %o7
|
||||||
tst %i4
|
sll %l0, 4, %l0
|
||||||
bz done
|
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
|
nop
|
||||||
|
st %f6, [%i2+6*4]
|
||||||
cmp %i3, FFI_TYPE_INT
|
nop
|
||||||
be,a done
|
E SPARC_RET_F_6
|
||||||
st %o0, [%i4] ! (delay)
|
st %f5, [%i2+5*4]
|
||||||
|
nop
|
||||||
cmp %i3, FFI_TYPE_FLOAT
|
st %f4, [%i2+4*4]
|
||||||
be,a done
|
nop
|
||||||
st %f0, [%i4+0] ! (delay)
|
E SPARC_RET_F_4
|
||||||
|
st %f3, [%i2+3*4]
|
||||||
cmp %i3, FFI_TYPE_DOUBLE
|
nop
|
||||||
be,a double
|
st %f2, [%i2+2*4]
|
||||||
st %f0, [%i4+0] ! (delay)
|
nop
|
||||||
|
E SPARC_RET_F_2
|
||||||
cmp %i3, FFI_TYPE_SINT8
|
st %f1, [%i2+4]
|
||||||
be,a sint8
|
st %f0, [%i2]
|
||||||
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:
|
|
||||||
ret
|
ret
|
||||||
restore
|
restore
|
||||||
|
E SP_V8_RET_CPLX8
|
||||||
double:
|
stb %o0, [%i2+1]
|
||||||
st %f1, [%i4+4]
|
b 10f
|
||||||
|
srl %o0, 8, %o0
|
||||||
|
E SPARC_RET_F_1
|
||||||
|
st %f0, [%i2]
|
||||||
ret
|
ret
|
||||||
restore
|
restore
|
||||||
|
|
||||||
sint8:
|
.align 8
|
||||||
sra %o0, 24, %o0
|
9: sth %o0, [%i2]
|
||||||
st %o0, [%i4+0]
|
|
||||||
ret
|
ret
|
||||||
restore
|
restore
|
||||||
|
.align 8
|
||||||
uint8:
|
10: stb %o0, [%i2]
|
||||||
srl %o0, 24, %o0
|
|
||||||
st %o0, [%i4+0]
|
|
||||||
ret
|
ret
|
||||||
restore
|
restore
|
||||||
|
|
||||||
sint16:
|
! Struct returning functions expect and skip the unimp here.
|
||||||
sra %o0, 16, %o0
|
! To make it worse, conforming callees examine the unimp and
|
||||||
st %o0, [%i4+0]
|
! 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
|
ret
|
||||||
restore
|
restore
|
||||||
|
.endr
|
||||||
|
|
||||||
uint16:
|
cfi_endproc
|
||||||
srl %o0, 16, %o0
|
.size C(ffi_call_v8),. - C(ffi_call_v8)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
#undef STACKFRAME
|
/* 16*4 register window + 1*4 struct return + 6*4 args backing store
|
||||||
#define STACKFRAME 104 /* 16*4 register window +
|
+ 8*4 return storage + 1*4 alignment. */
|
||||||
1*4 struct return +
|
#define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4)
|
||||||
6*4 args backing store +
|
|
||||||
3*4 locals */
|
|
||||||
|
|
||||||
/* ffi_closure_v8(...)
|
/* ffi_closure_v8(...)
|
||||||
|
|
||||||
Receives the closure argument in %g2. */
|
Receives the closure argument in %g2. */
|
||||||
|
|
||||||
.text
|
|
||||||
.align 8
|
|
||||||
.globl ffi_closure_v8
|
|
||||||
|
|
||||||
ffi_closure_v8:
|
|
||||||
#ifdef HAVE_AS_REGISTER_PSEUDO_OP
|
#ifdef HAVE_AS_REGISTER_PSEUDO_OP
|
||||||
.register %g2, #scratch
|
.register %g2, #scratch
|
||||||
#endif
|
#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.
|
! Store all of the potential argument registers in va_list format.
|
||||||
st %i0, [%fp+68+0]
|
st %i0, [%fp+68+0]
|
||||||
st %i1, [%fp+68+4]
|
st %i1, [%fp+68+4]
|
||||||
@@ -207,140 +271,91 @@ ffi_closure_v8:
|
|||||||
st %i5, [%fp+68+20]
|
st %i5, [%fp+68+20]
|
||||||
|
|
||||||
! Call ffi_closure_sparc_inner to do the bulk of the work.
|
! Call ffi_closure_sparc_inner to do the bulk of the work.
|
||||||
mov %g2, %o0
|
add %fp, -8*4, %o3
|
||||||
add %fp, -8, %o1
|
|
||||||
add %fp, 64, %o2
|
|
||||||
call ffi_closure_sparc_inner_v8
|
call ffi_closure_sparc_inner_v8
|
||||||
add %fp, -16, %o3
|
add %fp, 64, %o4
|
||||||
|
|
||||||
! Load up the return value in the proper type.
|
0: call 1f
|
||||||
! See ffi_prep_cif_machdep for the list of cases.
|
and %o0, SPARC_FLAG_RET_MASK, %o0
|
||||||
cmp %o0, FFI_TYPE_VOID
|
1: sll %o0, 4, %o0 ! o0 = o0 * 16
|
||||||
be done1
|
add %o7, %o0, %o7 ! o7 = 0b + o0*16
|
||||||
|
jmp %o7+(2f-0b)
|
||||||
|
add %fp, -8*4, %i2
|
||||||
|
|
||||||
cmp %o0, FFI_TYPE_INT
|
! Note that each entry is 4 insns, enforced by the E macro.
|
||||||
be done1
|
.align 16
|
||||||
ld [%fp-8], %i0
|
2:
|
||||||
|
E SPARC_RET_VOID
|
||||||
cmp %o0, FFI_TYPE_FLOAT
|
ret
|
||||||
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
|
|
||||||
restore
|
restore
|
||||||
done2:
|
E SPARC_RET_STRUCT
|
||||||
! Skip 'unimp'.
|
ld [%i2], %i0
|
||||||
jmp %i7+12
|
jmp %i7+12
|
||||||
restore
|
restore
|
||||||
.LLFE2:
|
E SPARC_RET_UINT8
|
||||||
|
ldub [%i2+3], %i0
|
||||||
.ffi_closure_v8_end:
|
ret
|
||||||
.size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8
|
restore
|
||||||
|
E SPARC_RET_SINT8
|
||||||
#ifdef SPARC64
|
ldsb [%i2+3], %i0
|
||||||
#define WS 8
|
ret
|
||||||
#define nword xword
|
restore
|
||||||
#define uanword uaxword
|
E SPARC_RET_UINT16
|
||||||
#else
|
lduh [%i2+2], %i0
|
||||||
#define WS 4
|
ret
|
||||||
#define nword long
|
restore
|
||||||
#define uanword uaword
|
E SPARC_RET_SINT16
|
||||||
#endif
|
ldsh [%i2+2], %i0
|
||||||
|
ret
|
||||||
#ifdef HAVE_RO_EH_FRAME
|
restore
|
||||||
.section ".eh_frame",#alloc
|
E SPARC_RET_UINT32
|
||||||
#else
|
ld [%i2], %i0
|
||||||
.section ".eh_frame",#alloc,#write
|
ret
|
||||||
#endif
|
restore
|
||||||
.LLframe1:
|
E SP_V8_RET_CPLX16
|
||||||
.uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
|
ld [%i2], %i0
|
||||||
.LLSCIE1:
|
ret
|
||||||
.uaword 0x0 ! CIE Identifier Tag
|
restore
|
||||||
.byte 0x1 ! CIE Version
|
E SPARC_RET_INT64
|
||||||
.ascii "zR\0" ! CIE Augmentation
|
ldd [%i2], %i0
|
||||||
.byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
|
ret
|
||||||
.byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor
|
restore
|
||||||
.byte 0xf ! CIE RA Column
|
E SPARC_RET_INT128
|
||||||
.byte 0x1 ! uleb128 0x1; Augmentation size
|
ldd [%i2], %i0
|
||||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
ldd [%i2+8], %i2
|
||||||
.byte 0x1b ! FDE Encoding (pcrel sdata4)
|
ret
|
||||||
#else
|
restore
|
||||||
.byte 0x50 ! FDE Encoding (aligned absolute)
|
E SPARC_RET_F_8
|
||||||
#endif
|
ld [%i2+7*4], %f7
|
||||||
.byte 0xc ! DW_CFA_def_cfa
|
nop
|
||||||
.byte 0xe ! uleb128 0xe
|
ld [%i2+6*4], %f6
|
||||||
.byte 0x0 ! uleb128 0x0
|
nop
|
||||||
.align WS
|
E SPARC_RET_F_6
|
||||||
.LLECIE1:
|
ld [%i2+5*4], %f5
|
||||||
.LLSFDE1:
|
nop
|
||||||
.uaword .LLEFDE1-.LLASFDE1 ! FDE Length
|
ld [%i2+4*4], %f4
|
||||||
.LLASFDE1:
|
nop
|
||||||
.uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
|
E SPARC_RET_F_4
|
||||||
#ifdef HAVE_AS_SPARC_UA_PCREL
|
ld [%i2+3*4], %f3
|
||||||
.uaword %r_disp32(.LLFB1)
|
nop
|
||||||
.uaword .LLFE1-.LLFB1 ! FDE address range
|
ld [%i2+2*4], %f2
|
||||||
#else
|
nop
|
||||||
.align WS
|
E SPARC_RET_F_2
|
||||||
.nword .LLFB1
|
ldd [%i2], %f0
|
||||||
.uanword .LLFE1-.LLFB1 ! FDE address range
|
ret
|
||||||
#endif
|
restore
|
||||||
.byte 0x0 ! uleb128 0x0; Augmentation size
|
E SP_V8_RET_CPLX8
|
||||||
.byte 0x4 ! DW_CFA_advance_loc4
|
lduh [%i2], %i0
|
||||||
.uaword .LLCFI0-.LLFB1
|
ret
|
||||||
.byte 0xd ! DW_CFA_def_cfa_register
|
restore
|
||||||
.byte 0x1e ! uleb128 0x1e
|
E SPARC_RET_F_1
|
||||||
.byte 0x2d ! DW_CFA_GNU_window_save
|
ld [%i2], %f0
|
||||||
.byte 0x9 ! DW_CFA_register
|
ret
|
||||||
.byte 0xf ! uleb128 0xf
|
restore
|
||||||
.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:
|
|
||||||
|
|
||||||
|
cfi_endproc
|
||||||
|
.size C(ffi_closure_v8), . - C(ffi_closure_v8)
|
||||||
|
#endif /* !SPARC64 */
|
||||||
#if defined __ELF__ && defined __linux__
|
#if defined __ELF__ && defined __linux__
|
||||||
.section .note.GNU-stack,"",@progbits
|
.section .note.GNU-stack,"",@progbits
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+279
-209
@@ -27,105 +27,178 @@
|
|||||||
#define LIBFFI_ASM
|
#define LIBFFI_ASM
|
||||||
#include <fficonfig.h>
|
#include <fficonfig.h>
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
|
#include <ffi_cfi.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
#ifdef SPARC64
|
#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 STACK_BIAS 2047
|
||||||
#define ARGS (128) /* Offset of register area in frame */
|
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 8
|
.align 8
|
||||||
.globl ffi_call_v9
|
.globl C(ffi_call_v9)
|
||||||
.globl _ffi_call_v9
|
.type C(ffi_call_v9),@function
|
||||||
|
FFI_HIDDEN(C(ffi_call_v9))
|
||||||
|
|
||||||
ffi_call_v9:
|
C(ffi_call_v9):
|
||||||
_ffi_call_v9:
|
cfi_startproc
|
||||||
.LLFB1:
|
save %sp, %o4, %sp
|
||||||
save %sp, -STACKFRAME, %sp
|
cfi_def_cfa_register(%fp)
|
||||||
.LLCFI0:
|
cfi_window_save
|
||||||
|
|
||||||
sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
|
mov %i0, %o0 ! copy cif
|
||||||
add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of
|
add %sp, STACK_BIAS+128+48, %o1 ! load args area
|
||||||
! frame to set up
|
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
|
andcc %o0, SPARC_FLAG_FP_ARGS, %g0 ! need fp regs?
|
||||||
call %i0
|
add %sp, 48, %sp ! deallocate prep frame
|
||||||
mov %i1, %o1 ! (delay)
|
be,pt %xcc, 1f
|
||||||
brz,pt %o0, 1f
|
mov %o0, %l0 ! save flags
|
||||||
ldx [%l0+ARGS], %o0 ! call foreign function
|
|
||||||
|
|
||||||
ldd [%l0+ARGS], %f0
|
ldd [%sp+STACK_BIAS+128], %f0 ! load all fp arg regs
|
||||||
ldd [%l0+ARGS+8], %f2
|
ldd [%sp+STACK_BIAS+128+8], %f2
|
||||||
ldd [%l0+ARGS+16], %f4
|
ldd [%sp+STACK_BIAS+128+16], %f4
|
||||||
ldd [%l0+ARGS+24], %f6
|
ldd [%sp+STACK_BIAS+128+24], %f6
|
||||||
ldd [%l0+ARGS+32], %f8
|
ldd [%sp+STACK_BIAS+128+32], %f8
|
||||||
ldd [%l0+ARGS+40], %f10
|
ldd [%sp+STACK_BIAS+128+40], %f10
|
||||||
ldd [%l0+ARGS+48], %f12
|
ldd [%sp+STACK_BIAS+128+48], %f12
|
||||||
ldd [%l0+ARGS+56], %f14
|
ldd [%sp+STACK_BIAS+128+56], %f14
|
||||||
ldd [%l0+ARGS+64], %f16
|
ldd [%sp+STACK_BIAS+128+64], %f16
|
||||||
ldd [%l0+ARGS+72], %f18
|
ldd [%sp+STACK_BIAS+128+72], %f18
|
||||||
ldd [%l0+ARGS+80], %f20
|
ldd [%sp+STACK_BIAS+128+80], %f20
|
||||||
ldd [%l0+ARGS+88], %f22
|
ldd [%sp+STACK_BIAS+128+88], %f22
|
||||||
ldd [%l0+ARGS+96], %f24
|
ldd [%sp+STACK_BIAS+128+96], %f24
|
||||||
ldd [%l0+ARGS+104], %f26
|
ldd [%sp+STACK_BIAS+128+104], %f26
|
||||||
ldd [%l0+ARGS+112], %f28
|
ldd [%sp+STACK_BIAS+128+112], %f28
|
||||||
ldd [%l0+ARGS+120], %f30
|
ldd [%sp+STACK_BIAS+128+120], %f30
|
||||||
|
|
||||||
1: ldx [%l0+ARGS+8], %o1
|
1: ldx [%sp+STACK_BIAS+128], %o0 ! load all int arg regs
|
||||||
ldx [%l0+ARGS+16], %o2
|
ldx [%sp+STACK_BIAS+128+8], %o1
|
||||||
ldx [%l0+ARGS+24], %o3
|
ldx [%sp+STACK_BIAS+128+16], %o2
|
||||||
ldx [%l0+ARGS+32], %o4
|
ldx [%sp+STACK_BIAS+128+24], %o3
|
||||||
ldx [%l0+ARGS+40], %o5
|
ldx [%sp+STACK_BIAS+128+32], %o4
|
||||||
call %i5
|
ldx [%sp+STACK_BIAS+128+40], %o5
|
||||||
sub %l0, STACK_BIAS, %sp ! (delay) switch to frame
|
call %i1
|
||||||
|
mov %i5, %g5 ! load static chain
|
||||||
|
|
||||||
! If the return value pointer is NULL, assume no return value.
|
0: call 1f ! load pc in %o7
|
||||||
brz,pn %i4, done
|
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
|
nop
|
||||||
|
|
||||||
cmp %i3, FFI_TYPE_INT
|
.align 16
|
||||||
be,a,pt %icc, done
|
2:
|
||||||
stx %o0, [%i4+0] ! (delay)
|
E SPARC_RET_VOID
|
||||||
|
return %i7+8
|
||||||
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
|
|
||||||
nop
|
nop
|
||||||
std %f0, [%i4+0]
|
E SPARC_RET_STRUCT
|
||||||
std %f2, [%i4+8]
|
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
|
! Finish the SPARC_RET_STRUCT sequence.
|
||||||
restore
|
.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:
|
! Copy the structure into place.
|
||||||
/* This will not work correctly for unions. */
|
srl %l0, SPARC_SIZEMASK_SHIFT, %o0 ! load size_mask
|
||||||
stx %o0, [%i4+0]
|
mov %i2, %o1 ! load dst
|
||||||
stx %o1, [%i4+8]
|
mov %l2, %o2 ! load src_gp
|
||||||
stx %o2, [%i4+16]
|
call C(ffi_struct_float_copy)
|
||||||
stx %o3, [%i4+24]
|
add %l2, 32, %o3 ! load src_fp
|
||||||
std %f0, [%i4+32]
|
|
||||||
std %f2, [%i4+40]
|
|
||||||
std %f4, [%i4+48]
|
|
||||||
std %f6, [%i4+56]
|
|
||||||
ret
|
|
||||||
restore
|
|
||||||
.LLFE1:
|
|
||||||
|
|
||||||
.ffi_call_v9_end:
|
return %i7+8
|
||||||
.size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9
|
nop
|
||||||
|
|
||||||
|
cfi_endproc
|
||||||
|
.size C(ffi_call_v9), . - C(ffi_call_v9)
|
||||||
|
|
||||||
|
|
||||||
#undef STACKFRAME
|
#undef STACKFRAME
|
||||||
@@ -138,15 +211,40 @@ dostruct:
|
|||||||
|
|
||||||
Receives the closure argument in %g1. */
|
Receives the closure argument in %g1. */
|
||||||
|
|
||||||
.text
|
|
||||||
.align 8
|
.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:
|
C(ffi_go_closure_v9):
|
||||||
.LLFB2:
|
cfi_startproc
|
||||||
save %sp, -STACKFRAME, %sp
|
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.
|
! Store all of the potential argument registers in va_list format.
|
||||||
stx %i0, [FP+128+0]
|
stx %i0, [FP+128+0]
|
||||||
stx %i1, [FP+128+8]
|
stx %i1, [FP+128+8]
|
||||||
@@ -174,134 +272,106 @@ ffi_closure_v9:
|
|||||||
std %f30, [FP-8]
|
std %f30, [FP-8]
|
||||||
|
|
||||||
! Call ffi_closure_sparc_inner to do the bulk of the work.
|
! Call ffi_closure_sparc_inner to do the bulk of the work.
|
||||||
mov %g1, %o0
|
add %fp, STACK_BIAS-160, %o3
|
||||||
add %fp, STACK_BIAS-160, %o1
|
add %fp, STACK_BIAS+128, %o4
|
||||||
add %fp, STACK_BIAS+128, %o2
|
call C(ffi_closure_sparc_inner_v9)
|
||||||
call ffi_closure_sparc_inner_v9
|
add %fp, STACK_BIAS-128, %o5
|
||||||
add %fp, STACK_BIAS-128, %o3
|
|
||||||
|
|
||||||
! Load up the return value in the proper type.
|
0: call 1f ! load pc in %o7
|
||||||
! See ffi_prep_cif_machdep for the list of cases.
|
and %o0, SPARC_FLAG_RET_MASK, %o0
|
||||||
cmp %o0, FFI_TYPE_VOID
|
1: sll %o0, 4, %o0 ! o2 = i2 * 16
|
||||||
be,pn %icc, done1
|
add %o7, %o0, %o7 ! o7 = 0b + i2*16
|
||||||
|
jmp %o7+(2f-0b)
|
||||||
|
nop
|
||||||
|
|
||||||
cmp %o0, FFI_TYPE_INT
|
! Note that we cannot load the data in the delay slot of
|
||||||
be,pn %icc, integer
|
! the return insn because the data is in the stack frame
|
||||||
|
! that is deallocated by the return.
|
||||||
cmp %o0, FFI_TYPE_FLOAT
|
.align 16
|
||||||
be,a,pn %icc, done1
|
2:
|
||||||
ld [FP-160], %f0
|
E SPARC_RET_VOID
|
||||||
|
return %i7+8
|
||||||
cmp %o0, FFI_TYPE_DOUBLE
|
nop
|
||||||
be,a,pn %icc, done1
|
E SPARC_RET_STRUCT
|
||||||
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:
|
|
||||||
ldx [FP-160], %i0
|
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:
|
! Finish the SPARC_RET_STRUCT sequence.
|
||||||
ret
|
.align 8
|
||||||
restore
|
8: ldd [FP-152], %f2
|
||||||
|
ldx [FP-144], %i2
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
ldd [FP-144], %f4
|
||||||
longdouble1:
|
ldx [FP-136], %i3
|
||||||
ldd [FP-152], %f2
|
ldd [FP-136], %f6
|
||||||
ret
|
return %i7+8
|
||||||
restore
|
nop
|
||||||
#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
|
|
||||||
|
|
||||||
|
cfi_endproc
|
||||||
|
.size C(ffi_closure_v9), . - C(ffi_closure_v9)
|
||||||
|
#endif /* SPARC64 */
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
.section .note.GNU-stack,"",@progbits
|
.section .note.GNU-stack,"",@progbits
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+559
-797
File diff suppressed because it is too large
Load Diff
+233
-96
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "internal64.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
@@ -62,10 +64,12 @@ struct register_args
|
|||||||
/* Registers for argument passing. */
|
/* Registers for argument passing. */
|
||||||
UINT64 gpr[MAX_GPR_REGS];
|
UINT64 gpr[MAX_GPR_REGS];
|
||||||
union big_int_union sse[MAX_SSE_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,
|
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
|
/* All reference to register classes here is identical to the code in
|
||||||
gcc/config/i386/i386.c. Do *not* change one without the other. */
|
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_UINT64:
|
||||||
case FFI_TYPE_SINT64:
|
case FFI_TYPE_SINT64:
|
||||||
case FFI_TYPE_POINTER:
|
case FFI_TYPE_POINTER:
|
||||||
|
do_integer:
|
||||||
{
|
{
|
||||||
size_t size = byte_offset + type->size;
|
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)
|
else if (size <= 16)
|
||||||
{
|
{
|
||||||
classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
|
classes[0] = classes[1] = X86_64_INTEGER_CLASS;
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -297,11 +302,42 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
|||||||
}
|
}
|
||||||
return words;
|
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:
|
case FFI_TYPE_FLOAT:
|
||||||
FFI_ASSERT(0);
|
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
|
/* 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;
|
int gprcount, ssecount, i, avn, ngpr, nsse, flags;
|
||||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
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;
|
gprcount = ssecount = 0;
|
||||||
|
|
||||||
flags = cif->rtype->type;
|
rtype = cif->rtype;
|
||||||
if (flags != FFI_TYPE_VOID)
|
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);
|
n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
{
|
{
|
||||||
@@ -370,22 +450,62 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||||||
memory is the first argument. Allocate a register for it. */
|
memory is the first argument. Allocate a register for it. */
|
||||||
gprcount++;
|
gprcount++;
|
||||||
/* We don't have to do anything in asm for the return. */
|
/* 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 sse0 = SSE_CLASS_P (classes[0]);
|
||||||
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
|
|
||||||
if (sse0 && !sse1)
|
if (rtype_size == 4 && sse0)
|
||||||
flags |= 1 << 8;
|
flags = UNIX64_RET_XMM32;
|
||||||
else if (!sse0 && sse1)
|
else if (rtype_size == 8)
|
||||||
flags |= 1 << 9;
|
flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
|
||||||
else if (sse0 && sse1)
|
else
|
||||||
flags |= 1 << 10;
|
{
|
||||||
/* Mark the true size of the structure. */
|
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
|
||||||
flags |= cif->rtype->size << 12;
|
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.
|
/* 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)
|
if (ssecount)
|
||||||
flags |= 1 << 11;
|
flags |= UNIX64_FLAG_XMM_ARGS;
|
||||||
|
|
||||||
cif->flags = flags;
|
cif->flags = flags;
|
||||||
cif->bytes = (unsigned)ALIGN (bytes, 8);
|
cif->bytes = ALIGN (bytes, 8);
|
||||||
|
|
||||||
return FFI_OK;
|
return FFI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||||
|
void **avalue, void *closure)
|
||||||
{
|
{
|
||||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||||
char *stack, *argp;
|
char *stack, *argp;
|
||||||
ffi_type **arg_types;
|
ffi_type **arg_types;
|
||||||
int gprcount, ssecount, ngpr, nsse, i, avn;
|
int gprcount, ssecount, ngpr, nsse, i, avn, flags;
|
||||||
_Bool ret_in_memory;
|
|
||||||
struct register_args *reg_args;
|
struct register_args *reg_args;
|
||||||
|
|
||||||
/* Can't call 32-bit mode from 64-bit mode. */
|
/* Can't call 32-bit mode from 64-bit mode. */
|
||||||
FFI_ASSERT (cif->abi == FFI_UNIX64);
|
FFI_ASSERT (cif->abi == FFI_UNIX64);
|
||||||
|
|
||||||
/* If the return value is a struct and we don't have a return value
|
/* 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
|
address then we need to make one. Otherwise we can ignore it. */
|
||||||
VOID above in ffi_prep_cif_machdep. */
|
flags = cif->flags;
|
||||||
ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
|
if (rvalue == NULL)
|
||||||
&& (cif->flags & 0xff) == FFI_TYPE_VOID);
|
{
|
||||||
if (rvalue == NULL && ret_in_memory)
|
if (flags & UNIX64_FLAG_RET_IN_MEM)
|
||||||
rvalue = alloca (cif->rtype->size);
|
rvalue = alloca (cif->rtype->size);
|
||||||
|
else
|
||||||
|
flags = UNIX64_RET_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate the space for the arguments, plus 4 words of temp space. */
|
/* Allocate the space for the arguments, plus 4 words of temp space. */
|
||||||
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
|
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
|
||||||
reg_args = (struct register_args *) stack;
|
reg_args = (struct register_args *) stack;
|
||||||
argp = stack + sizeof (struct register_args);
|
argp = stack + sizeof (struct register_args);
|
||||||
|
|
||||||
|
reg_args->r10 = (uintptr_t) closure;
|
||||||
|
|
||||||
gprcount = ssecount = 0;
|
gprcount = ssecount = 0;
|
||||||
|
|
||||||
/* If the return value is passed in memory, add the pointer as the
|
/* If the return value is passed in memory, add the pointer as the
|
||||||
first integer argument. */
|
first integer argument. */
|
||||||
if (ret_in_memory)
|
if (flags & UNIX64_FLAG_RET_IN_MEM)
|
||||||
reg_args->gpr[gprcount++] = (unsigned long) rvalue;
|
reg_args->gpr[gprcount++] = (unsigned long) rvalue;
|
||||||
|
|
||||||
avn = cif->nargs;
|
avn = cif->nargs;
|
||||||
@@ -494,17 +620,17 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
|||||||
switch (arg_types[i]->type)
|
switch (arg_types[i]->type)
|
||||||
{
|
{
|
||||||
case FFI_TYPE_SINT8:
|
case FFI_TYPE_SINT8:
|
||||||
*(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
|
reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
|
||||||
break;
|
break;
|
||||||
case FFI_TYPE_SINT16:
|
case FFI_TYPE_SINT16:
|
||||||
*(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
|
reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
|
||||||
break;
|
break;
|
||||||
case FFI_TYPE_SINT32:
|
case FFI_TYPE_SINT32:
|
||||||
*(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
|
reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
reg_args->gpr[gprcount] = 0;
|
reg_args->gpr[gprcount] = 0;
|
||||||
memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8);
|
memcpy (®_args->gpr[gprcount], a, size);
|
||||||
}
|
}
|
||||||
gprcount++;
|
gprcount++;
|
||||||
break;
|
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),
|
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_status
|
||||||
ffi_prep_closure_loc (ffi_closure* closure,
|
ffi_prep_closure_loc (ffi_closure* closure,
|
||||||
@@ -536,29 +676,27 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||||||
void *user_data,
|
void *user_data,
|
||||||
void *codeloc)
|
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. */
|
if (cif->abi != FFI_UNIX64)
|
||||||
{
|
return FFI_BAD_ABI;
|
||||||
int abi = cif->abi;
|
|
||||||
if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
|
|
||||||
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 */
|
memcpy (tramp, trampoline, sizeof(trampoline));
|
||||||
*((unsigned long long * volatile) &tramp[1])
|
*(UINT64 *)(tramp + 16) = (uintptr_t)dest;
|
||||||
= (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 */
|
|
||||||
|
|
||||||
closure->cif = cif;
|
closure->cif = cif;
|
||||||
closure->fun = fun;
|
closure->fun = fun;
|
||||||
@@ -567,49 +705,29 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||||||
return FFI_OK;
|
return FFI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int FFI_HIDDEN
|
||||||
ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
|
ffi_closure_unix64_inner(ffi_cif *cif,
|
||||||
struct register_args *reg_args, char *argp)
|
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||||
|
void *user_data,
|
||||||
|
void *rvalue,
|
||||||
|
struct register_args *reg_args,
|
||||||
|
char *argp)
|
||||||
{
|
{
|
||||||
ffi_cif *cif;
|
|
||||||
void **avalue;
|
void **avalue;
|
||||||
ffi_type **arg_types;
|
ffi_type **arg_types;
|
||||||
long i, avn;
|
long i, avn;
|
||||||
int gprcount, ssecount, ngpr, nsse;
|
int gprcount, ssecount, ngpr, nsse;
|
||||||
int ret;
|
int flags;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
avn = cif->nargs;
|
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)
|
for (i = 0; i < avn; ++i)
|
||||||
{
|
{
|
||||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||||
@@ -667,10 +785,29 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke the closure. */
|
/* 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. */
|
/* 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__ */
|
#endif /* __x86_64__ */
|
||||||
|
|||||||
+35
-48
@@ -76,44 +76,40 @@ typedef signed long ffi_sarg;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum ffi_abi {
|
typedef enum ffi_abi {
|
||||||
|
#if defined(X86_WIN64)
|
||||||
FFI_FIRST_ABI = 0,
|
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_WIN64,
|
||||||
FFI_LAST_ABI,
|
FFI_LAST_ABI,
|
||||||
FFI_DEFAULT_ABI = FFI_WIN64
|
FFI_DEFAULT_ABI = FFI_WIN64
|
||||||
|
|
||||||
#else
|
#elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
|
||||||
/* ---- Intel x86 and AMD x86-64 - */
|
FFI_FIRST_ABI = 1,
|
||||||
FFI_SYSV,
|
FFI_UNIX64,
|
||||||
FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
|
|
||||||
FFI_THISCALL,
|
|
||||||
FFI_FASTCALL,
|
|
||||||
FFI_STDCALL,
|
|
||||||
FFI_PASCAL,
|
|
||||||
FFI_REGISTER,
|
|
||||||
FFI_LAST_ABI,
|
FFI_LAST_ABI,
|
||||||
#if defined(__i386__) || defined(__i386)
|
|
||||||
FFI_DEFAULT_ABI = FFI_SYSV
|
|
||||||
#else
|
|
||||||
FFI_DEFAULT_ABI = FFI_UNIX64
|
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
|
#endif
|
||||||
} ffi_abi;
|
} ffi_abi;
|
||||||
#endif
|
#endif
|
||||||
@@ -121,29 +117,20 @@ typedef enum ffi_abi {
|
|||||||
/* ---- Definitions for closures ----------------------------------------- */
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
#define FFI_CLOSURES 1
|
#define FFI_CLOSURES 1
|
||||||
|
#define FFI_GO_CLOSURES 1
|
||||||
|
|
||||||
#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 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_2B (FFI_TYPE_LAST + 2)
|
||||||
#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
|
#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
|
||||||
#define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
|
#define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
|
||||||
|
|
||||||
#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
|
#if defined (X86_64) || defined(X86_WIN64) \
|
||||||
#define FFI_TRAMPOLINE_SIZE 24
|
|| (defined (__x86_64__) && defined (X86_DARWIN))
|
||||||
#define FFI_NATIVE_RAW_API 0
|
# define FFI_TRAMPOLINE_SIZE 24
|
||||||
|
# define FFI_NATIVE_RAW_API 0
|
||||||
#else
|
#else
|
||||||
#ifdef X86_WIN32
|
# define FFI_TRAMPOLINE_SIZE 12
|
||||||
#define FFI_TRAMPOLINE_SIZE 52
|
# define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
|
||||||
#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
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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
|
#define LIBFFI_ASM
|
||||||
#include <fficonfig.h>
|
#include <fficonfig.h>
|
||||||
#include <ffi.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,
|
/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
|
||||||
void *raddr, void (*fnaddr)(void));
|
void *raddr, void (*fnaddr)(void));
|
||||||
@@ -40,12 +53,13 @@
|
|||||||
for this function. This has been allocated by ffi_call. We also
|
for this function. This has been allocated by ffi_call. We also
|
||||||
deallocate some of the stack that has been alloca'd. */
|
deallocate some of the stack that has been alloca'd. */
|
||||||
|
|
||||||
.align 2
|
.align 8
|
||||||
.globl ffi_call_unix64
|
.globl ffi_call_unix64
|
||||||
.type ffi_call_unix64,@function
|
.type ffi_call_unix64,@function
|
||||||
|
FFI_HIDDEN(ffi_call_unix64)
|
||||||
|
|
||||||
ffi_call_unix64:
|
ffi_call_unix64:
|
||||||
.LUW0:
|
cfi_startproc
|
||||||
movq (%rsp), %r10 /* Load return address. */
|
movq (%rsp), %r10 /* Load return address. */
|
||||||
leaq (%rdi, %rsi), %rax /* Find local stack base. */
|
leaq (%rdi, %rsi), %rax /* Find local stack base. */
|
||||||
movq %rdx, (%rax) /* Save flags. */
|
movq %rdx, (%rax) /* Save flags. */
|
||||||
@@ -53,24 +67,36 @@ ffi_call_unix64:
|
|||||||
movq %rbp, 16(%rax) /* Save old frame pointer. */
|
movq %rbp, 16(%rax) /* Save old frame pointer. */
|
||||||
movq %r10, 24(%rax) /* Relocate return address. */
|
movq %r10, 24(%rax) /* Relocate return address. */
|
||||||
movq %rax, %rbp /* Finalize local stack frame. */
|
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 %rdi, %r10 /* Save a copy of the register area. */
|
||||||
movq %r8, %r11 /* Save a copy of the target fn. */
|
movq %r8, %r11 /* Save a copy of the target fn. */
|
||||||
movl %r9d, %eax /* Set number of SSE registers. */
|
movl %r9d, %eax /* Set number of SSE registers. */
|
||||||
|
|
||||||
/* Load up all argument registers. */
|
/* Load up all argument registers. */
|
||||||
movq (%r10), %rdi
|
movq (%r10), %rdi
|
||||||
movq 8(%r10), %rsi
|
movq 0x08(%r10), %rsi
|
||||||
movq 16(%r10), %rdx
|
movq 0x10(%r10), %rdx
|
||||||
movq 24(%r10), %rcx
|
movq 0x18(%r10), %rcx
|
||||||
movq 32(%r10), %r8
|
movq 0x20(%r10), %r8
|
||||||
movq 40(%r10), %r9
|
movq 0x28(%r10), %r9
|
||||||
|
movl 0xb0(%r10), %eax
|
||||||
testl %eax, %eax
|
testl %eax, %eax
|
||||||
jnz .Lload_sse
|
jnz .Lload_sse
|
||||||
.Lret_from_load_sse:
|
.Lret_from_load_sse:
|
||||||
|
|
||||||
/* Deallocate the reg arg area. */
|
/* Deallocate the reg arg area, except for r10, then load via pop. */
|
||||||
leaq 176(%r10), %rsp
|
leaq 0xb8(%r10), %rsp
|
||||||
|
popq %r10
|
||||||
|
|
||||||
/* Call the user function. */
|
/* Call the user function. */
|
||||||
call *%r11
|
call *%r11
|
||||||
@@ -81,352 +107,304 @@ ffi_call_unix64:
|
|||||||
movq 0(%rbp), %rcx /* Reload flags. */
|
movq 0(%rbp), %rcx /* Reload flags. */
|
||||||
movq 8(%rbp), %rdi /* Reload raddr. */
|
movq 8(%rbp), %rdi /* Reload raddr. */
|
||||||
movq 16(%rbp), %rbp /* Reload old frame pointer. */
|
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. */
|
/* The first byte of the flags contains the FFI_TYPE. */
|
||||||
|
cmpb $UNIX64_RET_LAST, %cl
|
||||||
movzbl %cl, %r10d
|
movzbl %cl, %r10d
|
||||||
leaq .Lstore_table(%rip), %r11
|
leaq 0f(%rip), %r11
|
||||||
movslq (%r11, %r10, 4), %r10
|
ja 9f
|
||||||
addq %r11, %r10
|
leaq (%r11, %r10, 8), %r10
|
||||||
|
|
||||||
|
/* Prep for the structure cases: scratch area in redzone. */
|
||||||
|
leaq -20(%rsp), %rsi
|
||||||
jmp *%r10
|
jmp *%r10
|
||||||
|
|
||||||
.Lstore_table:
|
.align 8
|
||||||
.long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */
|
0:
|
||||||
.long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */
|
E UNIX64_RET_VOID
|
||||||
.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:
|
|
||||||
ret
|
ret
|
||||||
.align 2
|
E UNIX64_RET_UINT8
|
||||||
|
movzbl %al, %eax
|
||||||
.Lst_uint8:
|
|
||||||
movzbq %al, %rax
|
|
||||||
movq %rax, (%rdi)
|
movq %rax, (%rdi)
|
||||||
ret
|
ret
|
||||||
.align 2
|
E UNIX64_RET_UINT16
|
||||||
.Lst_sint8:
|
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
|
movsbq %al, %rax
|
||||||
movq %rax, (%rdi)
|
movq %rax, (%rdi)
|
||||||
ret
|
ret
|
||||||
.align 2
|
E UNIX64_RET_SINT16
|
||||||
.Lst_uint16:
|
|
||||||
movzwq %ax, %rax
|
|
||||||
movq %rax, (%rdi)
|
|
||||||
.align 2
|
|
||||||
.Lst_sint16:
|
|
||||||
movswq %ax, %rax
|
movswq %ax, %rax
|
||||||
movq %rax, (%rdi)
|
movq %rax, (%rdi)
|
||||||
ret
|
ret
|
||||||
.align 2
|
E UNIX64_RET_SINT32
|
||||||
.Lst_uint32:
|
|
||||||
movl %eax, %eax
|
|
||||||
movq %rax, (%rdi)
|
|
||||||
.align 2
|
|
||||||
.Lst_sint32:
|
|
||||||
cltq
|
cltq
|
||||||
movq %rax, (%rdi)
|
movq %rax, (%rdi)
|
||||||
ret
|
ret
|
||||||
.align 2
|
E UNIX64_RET_INT64
|
||||||
.Lst_int64:
|
|
||||||
movq %rax, (%rdi)
|
movq %rax, (%rdi)
|
||||||
ret
|
ret
|
||||||
|
E UNIX64_RET_XMM32
|
||||||
.align 2
|
movd %xmm0, (%rdi)
|
||||||
.Lst_float:
|
|
||||||
movss %xmm0, (%rdi)
|
|
||||||
ret
|
ret
|
||||||
.align 2
|
E UNIX64_RET_XMM64
|
||||||
.Lst_double:
|
movq %xmm0, (%rdi)
|
||||||
movsd %xmm0, (%rdi)
|
|
||||||
ret
|
ret
|
||||||
.Lst_ldouble:
|
E UNIX64_RET_X87
|
||||||
fstpt (%rdi)
|
fstpt (%rdi)
|
||||||
ret
|
ret
|
||||||
|
E UNIX64_RET_X87_2
|
||||||
.align 2
|
fstpt (%rdi)
|
||||||
.Lst_struct:
|
fstpt 16(%rdi)
|
||||||
leaq -20(%rsp), %rsi /* Scratch area in redzone. */
|
ret
|
||||||
|
E UNIX64_RET_ST_XMM0_RAX
|
||||||
/* We have to locate the values now, and since we don't want to
|
movq %rax, 8(%rsi)
|
||||||
write too much data into the user's return value, we spill the
|
jmp 3f
|
||||||
value to a 16 byte scratch area first. Bits 8, 9, and 10
|
E UNIX64_RET_ST_RAX_XMM0
|
||||||
control where the values are located. Only one of the three
|
movq %xmm0, 8(%rsi)
|
||||||
bits will be set; see ffi_prep_cif_machdep for the pattern. */
|
jmp 2f
|
||||||
movd %xmm0, %r10
|
E UNIX64_RET_ST_XMM0_XMM1
|
||||||
movd %xmm1, %r11
|
movq %xmm1, 8(%rsi)
|
||||||
testl $0x100, %ecx
|
jmp 3f
|
||||||
cmovnz %rax, %rdx
|
E UNIX64_RET_ST_RAX_RDX
|
||||||
cmovnz %r10, %rax
|
|
||||||
testl $0x200, %ecx
|
|
||||||
cmovnz %r10, %rdx
|
|
||||||
testl $0x400, %ecx
|
|
||||||
cmovnz %r10, %rax
|
|
||||||
cmovnz %r11, %rdx
|
|
||||||
movq %rax, (%rsi)
|
|
||||||
movq %rdx, 8(%rsi)
|
movq %rdx, 8(%rsi)
|
||||||
|
2: movq %rax, (%rsi)
|
||||||
/* Bits 12-31 contain the true size of the structure. Copy from
|
shrl $UNIX64_SIZE_SHIFT, %ecx
|
||||||
the scratch area to the true destination. */
|
|
||||||
shrl $12, %ecx
|
|
||||||
rep movsb
|
rep movsb
|
||||||
ret
|
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.
|
/* Many times we can avoid loading any SSE registers at all.
|
||||||
It's not worth an indirect jump to load the exact set of
|
It's not worth an indirect jump to load the exact set of
|
||||||
SSE registers needed; zero or all is a good compromise. */
|
SSE registers needed; zero or all is a good compromise. */
|
||||||
.align 2
|
.align 2
|
||||||
.LUW3:
|
cfi_restore_state
|
||||||
.Lload_sse:
|
.Lload_sse:
|
||||||
movdqa 48(%r10), %xmm0
|
movdqa 0x30(%r10), %xmm0
|
||||||
movdqa 64(%r10), %xmm1
|
movdqa 0x40(%r10), %xmm1
|
||||||
movdqa 80(%r10), %xmm2
|
movdqa 0x50(%r10), %xmm2
|
||||||
movdqa 96(%r10), %xmm3
|
movdqa 0x60(%r10), %xmm3
|
||||||
movdqa 112(%r10), %xmm4
|
movdqa 0x70(%r10), %xmm4
|
||||||
movdqa 128(%r10), %xmm5
|
movdqa 0x80(%r10), %xmm5
|
||||||
movdqa 144(%r10), %xmm6
|
movdqa 0x90(%r10), %xmm6
|
||||||
movdqa 160(%r10), %xmm7
|
movdqa 0xa0(%r10), %xmm7
|
||||||
jmp .Lret_from_load_sse
|
jmp .Lret_from_load_sse
|
||||||
|
|
||||||
.LUW4:
|
cfi_endproc
|
||||||
.size ffi_call_unix64,.-ffi_call_unix64
|
.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
|
.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
|
.type ffi_closure_unix64,@function
|
||||||
|
FFI_HIDDEN(ffi_closure_unix64)
|
||||||
|
|
||||||
ffi_closure_unix64:
|
ffi_closure_unix64:
|
||||||
.LUW5:
|
cfi_startproc
|
||||||
/* The carry flag is set by the trampoline iff SSE registers
|
subq $ffi_closure_FS, %rsp
|
||||||
are used. Don't clobber it before the branch instruction. */
|
/* Note clang bug 21515: adjust_cfa_offset error across endproc. */
|
||||||
leaq -200(%rsp), %rsp
|
cfi_def_cfa_offset(ffi_closure_FS + 8)
|
||||||
.LUW6:
|
0:
|
||||||
movq %rdi, (%rsp)
|
movq %rdi, ffi_closure_OFS_G+0x00(%rsp)
|
||||||
movq %rsi, 8(%rsp)
|
movq %rsi, ffi_closure_OFS_G+0x08(%rsp)
|
||||||
movq %rdx, 16(%rsp)
|
movq %rdx, ffi_closure_OFS_G+0x10(%rsp)
|
||||||
movq %rcx, 24(%rsp)
|
movq %rcx, ffi_closure_OFS_G+0x18(%rsp)
|
||||||
movq %r8, 32(%rsp)
|
movq %r8, ffi_closure_OFS_G+0x20(%rsp)
|
||||||
movq %r9, 40(%rsp)
|
movq %r9, ffi_closure_OFS_G+0x28(%rsp)
|
||||||
jc .Lsave_sse
|
|
||||||
.Lret_from_save_sse:
|
|
||||||
|
|
||||||
movq %r10, %rdi
|
#ifdef __ILP32__
|
||||||
leaq 176(%rsp), %rsi
|
movl FFI_TRAMPOLINE_SIZE(%r10), %edi /* Load cif */
|
||||||
movq %rsp, %rdx
|
movl FFI_TRAMPOLINE_SIZE+4(%r10), %esi /* Load fun */
|
||||||
leaq 208(%rsp), %rcx
|
movl FFI_TRAMPOLINE_SIZE+8(%r10), %edx /* Load user_data */
|
||||||
call ffi_closure_unix64_inner@PLT
|
#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. */
|
/* Deallocate stack frame early; return value is now in redzone. */
|
||||||
addq $200, %rsp
|
addq $ffi_closure_FS, %rsp
|
||||||
.LUW7:
|
cfi_adjust_cfa_offset(-ffi_closure_FS)
|
||||||
|
|
||||||
/* The first byte of the return value contains the FFI_TYPE. */
|
/* The first byte of the return value contains the FFI_TYPE. */
|
||||||
|
cmpb $UNIX64_RET_LAST, %al
|
||||||
movzbl %al, %r10d
|
movzbl %al, %r10d
|
||||||
leaq .Lload_table(%rip), %r11
|
leaq 0f(%rip), %r11
|
||||||
movslq (%r11, %r10, 4), %r10
|
ja 9f
|
||||||
addq %r11, %r10
|
leaq (%r11, %r10, 8), %r10
|
||||||
|
leaq ffi_closure_RED_RVALUE(%rsp), %rsi
|
||||||
jmp *%r10
|
jmp *%r10
|
||||||
|
|
||||||
.Lload_table:
|
.align 8
|
||||||
.long .Lld_void-.Lload_table /* FFI_TYPE_VOID */
|
0:
|
||||||
.long .Lld_int32-.Lload_table /* FFI_TYPE_INT */
|
E UNIX64_RET_VOID
|
||||||
.long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */
|
ret
|
||||||
.long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */
|
E UNIX64_RET_UINT8
|
||||||
.long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */
|
movzbl (%rsi), %eax
|
||||||
.long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */
|
ret
|
||||||
.long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */
|
E UNIX64_RET_UINT16
|
||||||
.long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */
|
movzwl (%rsi), %eax
|
||||||
.long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */
|
ret
|
||||||
.long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */
|
E UNIX64_RET_UINT32
|
||||||
.long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */
|
movl (%rsi), %eax
|
||||||
.long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */
|
ret
|
||||||
.long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */
|
E UNIX64_RET_SINT8
|
||||||
.long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */
|
movsbl (%rsi), %eax
|
||||||
.long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */
|
ret
|
||||||
|
E UNIX64_RET_SINT16
|
||||||
.align 2
|
movswl (%rsi), %eax
|
||||||
.Lld_void:
|
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
|
ret
|
||||||
|
|
||||||
.align 2
|
9: call abort@PLT
|
||||||
.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
|
|
||||||
|
|
||||||
.align 2
|
cfi_endproc
|
||||||
.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:
|
|
||||||
.size ffi_closure_unix64,.-ffi_closure_unix64
|
.size ffi_closure_unix64,.-ffi_closure_unix64
|
||||||
|
|
||||||
#ifdef __GNUC__
|
.align 2
|
||||||
/* Only emit DWARF unwind info when building with the GNU toolchain. */
|
.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
|
ffi_go_closure_unix64_sse:
|
||||||
.section .eh_frame,"a",@unwind
|
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
|
#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
|
#endif
|
||||||
.Lframe1:
|
jmp .Ldo_closure
|
||||||
.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 */
|
|
||||||
|
|
||||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
cfi_endproc
|
||||||
.long .LUW1-.LUW0
|
.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__ */
|
#endif /* __x86_64__ */
|
||||||
|
|
||||||
#if defined __ELF__ && defined __linux__
|
#if defined __ELF__ && defined __linux__
|
||||||
.section .note.GNU-stack,"",@progbits
|
.section .note.GNU-stack,"",@progbits
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
-1351
File diff suppressed because it is too large
Load Diff
+192
-493
@@ -1,264 +1,16 @@
|
|||||||
#define LIBFFI_ASM
|
#define LIBFFI_ASM
|
||||||
#include <fficonfig.h>
|
#include <fficonfig.h>
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
|
#include <ffi_cfi.h>
|
||||||
|
|
||||||
/* Constants for ffi_call_win64 */
|
#if defined(HAVE_AS_CFI_PSEUDO_OP)
|
||||||
#define STACK 0
|
.cfi_sections .debug_frame
|
||||||
#define PREP_ARGS_FN 32
|
#endif
|
||||||
#define ECIF 40
|
|
||||||
#define CIF_BYTES 48
|
|
||||||
#define CIF_FLAGS 56
|
|
||||||
#define RVALUE 64
|
|
||||||
#define FN 72
|
|
||||||
|
|
||||||
/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *),
|
#define arg0 %rcx
|
||||||
extended_cif *ecif, unsigned bytes, unsigned flags,
|
#define arg1 %rdx
|
||||||
unsigned *rvalue, void (*fn)());
|
#define arg2 %r8
|
||||||
*/
|
#define arg3 %r9
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
#ifdef SYMBOL_UNDERSCORE
|
#ifdef SYMBOL_UNDERSCORE
|
||||||
#define SYMBOL_NAME(name) _##name
|
#define SYMBOL_NAME(name) _##name
|
||||||
@@ -266,255 +18,202 @@ END
|
|||||||
#define SYMBOL_NAME(name) name
|
#define SYMBOL_NAME(name) name
|
||||||
#endif
|
#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:
|
/* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10)
|
||||||
# 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)
|
|
||||||
|
|
||||||
.Lsecond:
|
Bit o trickiness here -- FRAME is the base of the stack frame
|
||||||
test $2, %r11
|
for this function. This has been allocated by ffi_call. We also
|
||||||
jne .Lsecond_is_float
|
deallocate some of the stack that has been alloca'd. */
|
||||||
mov %rdx, 16(%rsp)
|
|
||||||
jmp .Lthird
|
|
||||||
.Lsecond_is_float:
|
|
||||||
movlpd %xmm1, 16(%rsp)
|
|
||||||
|
|
||||||
.Lthird:
|
.align 8
|
||||||
test $4, %r11
|
.globl ffi_call_win64
|
||||||
jne .Lthird_is_float
|
|
||||||
mov %r8,24(%rsp)
|
|
||||||
jmp .Lfourth
|
|
||||||
.Lthird_is_float:
|
|
||||||
movlpd %xmm2, 24(%rsp)
|
|
||||||
|
|
||||||
.Lfourth:
|
.seh_proc ffi_call_win64
|
||||||
test $8, %r11
|
ffi_call_win64:
|
||||||
jne .Lfourth_is_float
|
cfi_startproc
|
||||||
mov %r9, 32(%rsp)
|
/* Set up the local stack frame and install it in rbp/rsp. */
|
||||||
jmp .Ldone
|
movq (%rsp), %rax
|
||||||
.Lfourth_is_float:
|
movq %rbp, (arg1)
|
||||||
movlpd %xmm3, 32(%rsp)
|
movq %rax, 8(arg1)
|
||||||
|
movq arg1, %rbp
|
||||||
.Ldone:
|
cfi_def_cfa(%rbp, 16)
|
||||||
.seh_stackalloc 40
|
cfi_rel_offset(%rbp, 0)
|
||||||
sub $40, %rsp
|
.seh_pushreg %rbp
|
||||||
|
.seh_setframe %rbp, 0
|
||||||
.seh_endprologue
|
.seh_endprologue
|
||||||
mov %rax, %rcx # context is first parameter
|
movq arg0, %rsp
|
||||||
mov %rsp, %rdx # stack is second parameter
|
|
||||||
add $48, %rdx # point to start of arguments
|
movq arg2, %r10
|
||||||
leaq SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax
|
|
||||||
callq *%rax # call the real closure function
|
/* Load all slots into both general and xmm registers. */
|
||||||
add $40, %rsp
|
movq (%rsp), %rcx
|
||||||
movq %rax, %xmm0 # If the closure returned a float,
|
movsd (%rsp), %xmm0
|
||||||
# ffi_closure_win64_inner wrote it to rax
|
movq 8(%rsp), %rdx
|
||||||
retq
|
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
|
.seh_endproc
|
||||||
|
|
||||||
.balign 16
|
|
||||||
.globl SYMBOL_NAME(ffi_call_win64)
|
/* 32 bytes of outgoing register stack space, 8 bytes of alignment,
|
||||||
.seh_proc SYMBOL_NAME(ffi_call_win64)
|
16 bytes of result, 32 bytes of xmm registers. */
|
||||||
SYMBOL_NAME(ffi_call_win64):
|
#define ffi_clo_FS (32+8+16+32)
|
||||||
# copy registers onto stack
|
#define ffi_clo_OFF_R (32+8)
|
||||||
mov %r9,32(%rsp)
|
#define ffi_clo_OFF_X (32+8+16)
|
||||||
mov %r8,24(%rsp)
|
|
||||||
mov %rdx,16(%rsp)
|
.align 8
|
||||||
mov %rcx,8(%rsp)
|
.globl ffi_go_closure_win64
|
||||||
.seh_pushreg rbp
|
|
||||||
push %rbp
|
.seh_proc ffi_go_closure_win64
|
||||||
.seh_stackalloc 48
|
ffi_go_closure_win64:
|
||||||
sub $48,%rsp
|
cfi_startproc
|
||||||
.seh_setframe rbp, 32
|
/* Save all integer arguments into the incoming reg stack space. */
|
||||||
lea 32(%rsp),%rbp
|
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
|
.seh_endprologue
|
||||||
|
|
||||||
mov CIF_BYTES(%rbp),%eax
|
/* Save all sse arguments into the stack frame. */
|
||||||
add $15, %rax
|
movsd %xmm0, ffi_clo_OFF_X(%rsp)
|
||||||
and $-16, %rax
|
movsd %xmm1, ffi_clo_OFF_X+8(%rsp)
|
||||||
cmpq $0x1000, %rax
|
movsd %xmm2, ffi_clo_OFF_X+16(%rsp)
|
||||||
jb Lch_done
|
movsd %xmm3, ffi_clo_OFF_X+24(%rsp)
|
||||||
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)
|
|
||||||
|
|
||||||
mov ECIF(%rbp), %rdx
|
leaq ffi_clo_OFF_R(%rsp), arg3
|
||||||
mov STACK(%rbp), %rcx
|
call ffi_closure_win64_inner
|
||||||
callq *PREP_ARGS_FN(%rbp)
|
|
||||||
|
|
||||||
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
|
addq $ffi_clo_FS, %rsp
|
||||||
movd %xmm3, %r9
|
cfi_adjust_cfa_offset(-ffi_clo_FS)
|
||||||
|
ret
|
||||||
|
|
||||||
movlpd 16(%rsp), %xmm2
|
cfi_endproc
|
||||||
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
|
|
||||||
.seh_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 ""
|
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 {
|
foreach test $ctlist {
|
||||||
unsupported "$test"
|
unsupported "$test"
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
run-many-tests $ctlist ""
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dg-finish
|
dg-finish
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
PR: none.
|
PR: none.
|
||||||
Originator: <hos@tamanegi.org> 20031203 */
|
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-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,8 @@
|
|||||||
Originator: Blake Chaffin 6/18/2007
|
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-do run { xfail strongarm*-*-* } } */
|
||||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
|
|
||||||
|
|||||||
@@ -6,5 +6,11 @@
|
|||||||
|
|
||||||
/* { dg-do run } */
|
/* { 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 "complex_defs_float.inc"
|
||||||
#include "cls_complex_va.inc"
|
#include "cls_complex_va.inc"
|
||||||
|
|||||||
@@ -4,12 +4,10 @@
|
|||||||
PR: none.
|
PR: none.
|
||||||
Originator: Blake Chaffin */
|
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
|
/* This test is known to PASS on armv7l-unknown-linux-gnueabihf, so I have
|
||||||
remove the xfail for arm*-*-* below, until we know more. */
|
remove the xfail for arm*-*-* below, until we know more. */
|
||||||
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
_Complex int f_complex(_Complex int c, int x, int *py)
|
_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;
|
*py += x;
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
Limitations: none.
|
Limitations: none.
|
||||||
PR: none.
|
PR: none.
|
||||||
Originator: From the original ffitest.c */
|
Originator: From the original ffitest.c */
|
||||||
|
/* { dg-do run } */
|
||||||
/* { dg-excess-errors "fails" { target x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
#include "float.h"
|
#include "float.h"
|
||||||
|
|||||||
@@ -5,11 +5,9 @@
|
|||||||
Originator: Blake Chaffin 6/18/2007
|
Originator: Blake Chaffin 6/18/2007
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* { dg-excess-errors "" { target x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
|
||||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
|
||||||
/* { dg-options -Wformat=0 { target moxie*-*-elf } } */
|
/* { dg-options -Wformat=0 { target moxie*-*-elf } } */
|
||||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,14 @@
|
|||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
#include <complex.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)
|
int main (void)
|
||||||
{
|
{
|
||||||
ffi_cif cif;
|
ffi_cif cif;
|
||||||
@@ -35,6 +39,6 @@ int main (void)
|
|||||||
printf ("%f,%fi vs %f,%fi\n",
|
printf ("%f,%fi vs %f,%fi\n",
|
||||||
T_CONV creal (rc), T_CONV cimag (rc),
|
T_CONV creal (rc), T_CONV cimag (rc),
|
||||||
T_CONV creal (rc2), T_CONV cimag (rc2));
|
T_CONV creal (rc2), T_CONV cimag (rc2));
|
||||||
CHECK(rc == c1 + c2 + in3 + c4);
|
CHECK(rc == rc2);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
Limitations: none.
|
Limitations: none.
|
||||||
PR: none.
|
PR: none.
|
||||||
Originator: <andreast@gcc.gnu.org> 20071113 */
|
Originator: <andreast@gcc.gnu.org> 20071113 */
|
||||||
|
/* { dg-do run } */
|
||||||
|
|
||||||
/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
|
||||||
#include "ffitest.h"
|
#include "ffitest.h"
|
||||||
|
|
||||||
static long double return_ldl(long double ldl)
|
static long double return_ldl(long double ldl)
|
||||||
|
|||||||
Reference in New Issue
Block a user