Merge branch 'go-closure' of https://github.com/rth7680/libffi into rth7680-go-closure

Conflicts:
	src/aarch64/ffi.c
This commit is contained in:
Richard Henderson
2014-11-12 07:51:12 -05:00
committed by Anthony Green
45 changed files with 6453 additions and 12197 deletions
+10 -16
View File
@@ -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
+16
View File
@@ -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,
+55
View File
@@ -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 */
+608 -877
View File
File diff suppressed because it is too large Load Diff
+6 -8
View File
@@ -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
+67
View File
@@ -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)
+305 -240
View File
@@ -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
#endif
.text .text
.globl CNAME(ffi_call_SYSV) .align 4
#ifdef __ELF__
.type CNAME(ffi_call_SYSV), #function
#endif
#ifdef __APPLE__
.align 2
#endif
/* ffi_call_SYSV() /* ffi_call_SYSV
extern void ffi_call_SYSV (void *stack, void *frame,
Create a stack frame, setup an argument context, call the callee void (*fn)(void), void *rvalue,
and extract the result. int flags, void *closure);
The maximum required argument stack size is provided,
ffi_call_SYSV() allocates that stack space then calls the
prepare_fn to populate register context and stack. The
argument passing registers are loaded from the register
context and the callee called, on return the register passing
register are saved back to the context. Our caller will
extract the return value from the final state of the saved
register context.
Prototype:
extern unsigned
ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
extended_cif *),
struct call_context *context,
extended_cif *,
size_t required_stack_size,
void (*fn)(void));
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);
stp x29, x30, [x1]
mov x29, x1
mov sp, x0
cfi_def_cfa_register(x29)
cfi_rel_offset (x29, 0) cfi_rel_offset (x29, 0)
cfi_rel_offset (x30, 8) 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 */
#endif
stp x3, x4, [x29, #16] /* save rvalue and flags */
stp x21, x22, [sp, #0] /* Load the vector argument passing registers, if necessary. */
cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS) tbz w4, #AARCH64_FLAG_ARG_V_BIT, 1f
cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS) ldp q0, q1, [sp, #0]
ldp q2, q3, [sp, #32]
stp x23, x24, [sp, #16] ldp q4, q5, [sp, #64]
cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS) ldp q6, q7, [sp, #96]
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: 1:
/* Load the core argument passing registers. */ /* Load the core argument passing registers, including
ldp x0, x1, [x21, #0] the structure return pointer. */
ldp x2, x3, [x21, #16] ldp x0, x1, [sp, #16*N_V_ARG_REG + 0]
ldp x4, x5, [x21, #32] ldp x2, x3, [sp, #16*N_V_ARG_REG + 16]
ldp x6, x7, [x21, #48] ldp x4, x5, [sp, #16*N_V_ARG_REG + 32]
ldp x6, x7, [sp, #16*N_V_ARG_REG + 48]
/* Don't forget x8 which may be holding the address of a return buffer. /* Deallocate the context, leaving the stacked arguments. */
*/ add sp, sp, #CALL_CONTEXT_SIZE
ldr x8, [x21, #8*8]
blr x24 blr x9 /* call fn */
/* Save the core argument passing registers. */ ldp x3, x4, [x29, #16] /* reload rvalue and flags */
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)
/* Partially deconstruct the stack frame. */
mov sp, x29 mov sp, x29
cfi_def_cfa_register (sp) cfi_def_cfa_register (sp)
ldp x29, x30, [x29]
ldp x29, x30, [sp], #16 /* Save the return value as directed. */
cfi_adjust_cfa_offset (-16) adr x5, 0f
cfi_restore (x29) and w4, w4, #AARCH64_RET_MASK
cfi_restore (x30) 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 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 cfi_endproc
.globl CNAME(ffi_call_SYSV)
#ifdef __ELF__ #ifdef __ELF__
.type CNAME(ffi_call_SYSV), #function
.hidden CNAME(ffi_call_SYSV)
.size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV) .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
#endif #endif
#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
/* 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
struct trampoline_data stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
{ cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
UINT64 *ffi_closure;
UINT64 flags;
};
This function uses the following stack frame layout:
==
saved x30(lr)
x29(fp)-> saved x29(fp)
saved x22
saved x21
...
sp -> call_context
==
Voila! */
.text
.globl CNAME(ffi_closure_SYSV)
#ifdef __APPLE__
.align 2
#endif
.cfi_startproc
CNAME(ffi_closure_SYSV):
stp x29, x30, [sp, #-16]!
cfi_adjust_cfa_offset (16)
cfi_rel_offset (x29, 0) cfi_rel_offset (x29, 0)
cfi_rel_offset (x30, 8) 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. */ /* Save the argument passing vector registers. */
stp q0, q1, [x21, #8*32 + 0] stp q0, q1, [sp, #16 + 0]
stp q2, q3, [x21, #8*32 + 32] stp q2, q3, [sp, #16 + 32]
stp q4, q5, [x21, #8*32 + 64] stp q4, q5, [sp, #16 + 64]
stp q6, q7, [x21, #8*32 + 96] stp q6, q7, [sp, #16 + 96]
1: b 0f
/* Load &ffi_closure.. */ cfi_endproc
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
.globl CNAME(ffi_closure_SYSV_V)
#ifdef __ELF__
.type CNAME(ffi_closure_SYSV_V), #function
.hidden CNAME(ffi_closure_SYSV_V)
.size CNAME(ffi_closure_SYSV_V), . - CNAME(ffi_closure_SYSV_V)
#endif
.align 4
cfi_startproc
CNAME(ffi_closure_SYSV):
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
cfi_rel_offset (x29, 0)
cfi_rel_offset (x30, 8)
0:
mov x29, sp
/* Save the argument passing core registers. */
stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
/* Load ffi_closure_inner arguments. */
ldp x0, x1, [x17, #FFI_TRAMPOLINE_SIZE] /* load cif, fn */
ldr x2, [x17, #FFI_TRAMPOLINE_SIZE+16] /* load user_data */
.Ldo_closure:
add x3, sp, #16 /* load context */
add x4, sp, #ffi_closure_SYSV_FS /* load stack */
add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
mov x6, x8 /* load struct_rval */
bl CNAME(ffi_closure_SYSV_inner) bl CNAME(ffi_closure_SYSV_inner)
/* Figure out if we should touch the vector registers. */ /* Load the return value as directed. */
ldr x0, [x22, #8] adr x1, 0f
tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f and w0, w0, #AARCH64_RET_MASK
add x1, x1, x0, lsl #3
add x3, sp, #16+CALL_CONTEXT_SIZE
br x1
/* Load the result passing vector registers. */ /* Note that each table entry is 2 insns, and thus 8 bytes. */
ldp q0, q1, [x21, #8*32 + 0] .align 4
ldp q2, q3, [x21, #8*32 + 32] 0: b 99f /* VOID */
ldp q4, q5, [x21, #8*32 + 64] nop
ldp q6, q7, [x21, #8*32 + 96] 1: ldr x0, [x3] /* INT64 */
1: b 99f
/* Load the result passing core registers. */ 2: ldp x0, x1, [x3] /* INT128 */
ldp x0, x1, [x21, #0] b 99f
ldp x2, x3, [x21, #16] 3: brk #1000 /* UNUSED */
ldp x4, x5, [x21, #32] nop
ldp x6, x7, [x21, #48] 4: brk #1000 /* UNUSED */
/* Note nothing useful is returned in x8. */ nop
5: brk #1000 /* UNUSED */
/* We are done, unwind our frame. */ nop
ldp x21, x22, [x29, #-16] 6: brk #1000 /* UNUSED */
cfi_restore (x21) nop
cfi_restore (x22) 7: brk #1000 /* UNUSED */
nop
mov sp, x29 8: ldr s3, [x3, #12] /* S4 */
cfi_def_cfa_register (sp) nop
9: ldr s2, [x2, #8] /* S3 */
ldp x29, x30, [sp], #16 nop
cfi_adjust_cfa_offset (-16) 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 (x29)
cfi_restore (x30) cfi_restore (x30)
ret ret
.cfi_endproc cfi_endproc
.globl CNAME(ffi_closure_SYSV)
#ifdef __ELF__ #ifdef __ELF__
.type CNAME(ffi_closure_SYSV), #function
.hidden CNAME(ffi_closure_SYSV)
.size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV) .size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV)
#endif #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 */
+336 -103
View File
@@ -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,
void *raddr, void (*fn)(void), void *closure)
FFI_HIDDEN; 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;
/* Set the return type flag */ if (cif->abi != FFI_OSF)
switch (cif->rtype->type) return FFI_BAD_ABI;
/* Compute the size of the argument area. */
for (i = 0, avn = cif->nargs; i < avn; i++)
{ {
case FFI_TYPE_STRUCT: 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_FLOAT:
case FFI_TYPE_DOUBLE: case FFI_TYPE_DOUBLE:
cif->flags = cif->rtype->type; case FFI_TYPE_LONGDOUBLE:
/* All take one 8 byte slot. */
bytes += 8;
break; break;
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_VOID:
/* 128-bit long double is returned in memory, like a struct. */ case FFI_TYPE_STRUCT:
cif->flags = 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; break;
default: default:
cif->flags = FFI_TYPE_INT; abort();
}
}
/* Set the return type flag */
rtype = cif->rtype;
switch (rtype->type)
{
case FFI_TYPE_VOID:
flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
break;
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
break;
case FFI_TYPE_FLOAT:
flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
break;
case FFI_TYPE_DOUBLE:
flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
break;
case FFI_TYPE_UINT8:
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
break;
case FFI_TYPE_SINT8:
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
break;
case FFI_TYPE_UINT16:
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
break;
case FFI_TYPE_SINT16:
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_POINTER:
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
break;
case FFI_TYPE_LONGDOUBLE:
case FFI_TYPE_STRUCT:
/* Passed in memory, with a hidden pointer. */
flags = ALPHA_RET_IN_MEM;
break;
case FFI_TYPE_COMPLEX:
itype = rtype->elements[0];
switch (itype->type)
{
case FFI_TYPE_FLOAT:
flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
break;
case FFI_TYPE_DOUBLE:
flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
break;
default:
if (rtype->size <= 8)
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
else
flags = ALPHA_RET_IN_MEM;
break; break;
} }
break;
default:
abort();
}
cif->flags = flags;
/* Include the hidden structure pointer in args requirement. */
if (flags == ALPHA_RET_IN_MEM)
bytes += 8;
/* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
if (bytes < 6*8)
bytes = 6*8;
cif->bytes = bytes;
return FFI_OK; 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;
ffi_type **arg_types;
/* If the return value is a struct and we don't have a return
value address then we need to make one. */
if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT)
rvalue = alloca(cif->rtype->size);
/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
if (cif->flags == FFI_TYPE_STRUCT)
*(void **) argp++ = rvalue;
i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
while (i < avn)
{
size_t size = (*arg_types)->size;
switch ((*arg_types)->type)
{ {
case FFI_TYPE_SINT8: case FFI_TYPE_SINT8:
*(SINT64 *) argp = *(SINT8 *)(* avalue); return *(SINT8 *)valp;
break;
case FFI_TYPE_UINT8: case FFI_TYPE_UINT8:
*(SINT64 *) argp = *(UINT8 *)(* avalue); return *(UINT8 *)valp;
break;
case FFI_TYPE_SINT16: case FFI_TYPE_SINT16:
*(SINT64 *) argp = *(SINT16 *)(* avalue); return *(SINT16 *)valp;
break;
case FFI_TYPE_UINT16: case FFI_TYPE_UINT16:
*(SINT64 *) argp = *(UINT16 *)(* avalue); return *(UINT16 *)valp;
break;
case FFI_TYPE_FLOAT:
if (argn < 6)
return lds(valp);
/* FALLTHRU */
case FFI_TYPE_INT:
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. */ /* Note that unsigned 32-bit quantities are sign extended. */
*(SINT64 *) argp = *(SINT32 *)(* avalue); return *(SINT32 *)valp;
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:
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); return *(UINT64 *)valp;
default:
abort();
}
}
static void
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
void **avalue, void *closure)
{
unsigned long *argp;
long i, avn, argn, flags = cif->flags;
ffi_type **arg_types;
void *frame;
/* If the return value is a struct and we don't have a return
value address then we need to make one. */
if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
rvalue = alloca(cif->rtype->size);
/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
frame += cif->bytes;
argn = 0;
if (flags == ALPHA_RET_IN_MEM)
argp[argn++] = (unsigned long)rvalue;
avn = cif->nargs;
arg_types = cif->arg_types;
for (i = 0, avn = cif->nargs; i < avn; i++)
{
ffi_type *ty = arg_types[i];
void *valp = avalue[i];
int type = ty->type;
size_t size;
switch (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:
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; flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
i++, arg_types++, avalue++; ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
} }
ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn); 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:
if (argn < 6)
{
/* Floats coming from registers need conversion from double /* Floats coming from registers need conversion from double
back to float format. */ back to float format. */
*(float *)&argp[argn - 6] = *(double *)&argp[argn - 6]; if (argn < 6)
avalue[i] = &argp[argn - 6]; {
valp = &argp[argn - 6];
sts(valp, 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;
} }
+4
View File
@@ -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
+23
View File
@@ -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
View File
@@ -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
+531 -419
View File
File diff suppressed because it is too large Load Diff
+4 -6
View File
@@ -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
-118
View File
@@ -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
+7
View File
@@ -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
+259 -415
View File
@@ -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. */
#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
#else
#define CNAME(x) x
#endif
#ifdef __APPLE__
#define ENTRY(x) .globl _##x; _##x:
#else
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
#endif /* __APPLE__ */
#endif
#ifdef __ELF__
#define LSYM(x) .x
#else
#define LSYM(x) x
#endif
/* Use the SOFTFP return value ABI on Mac OS X, as per the iOS ABI
Function Call Guide */
#ifdef __APPLE__
#define __SOFTFP__
#endif
/* We need a better way of testing for this, but for now, this is all
we can do. */
@ This selects the minimum architecture level required.
#define __ARM_ARCH__ 3
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 4
#endif
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5TEJ__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 5
#endif
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
|| defined(__ARM_ARCH_6M__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 6
#endif
/* GCC 4.8 provides __ARM_ARCH; construct it otherwise. */
#ifndef __ARM_ARCH
# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ # if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7EM__)
# undef __ARM_ARCH__ # define __ARM_ARCH 7
# define __ARM_ARCH__ 7 # elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
#endif || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
#if __ARM_ARCH__ >= 5 || defined(__ARM_ARCH_6M__)
# define call_reg(x) blx x # define __ARM_ARCH 6
#elif defined (__ARM_ARCH_4T__) # elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
# define call_reg(x) mov lr, pc ; bx x || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
# if defined(__thumb__) || defined(__THUMB_INTERWORK__) || defined(__ARM_ARCH_5TEJ__)
# define __INTERWORKING__ # define __ARM_ARCH 5
# endif
# else # else
# define call_reg(x) mov lr, pc ; mov pc, x # define __ARM_ARCH 4
# endif
#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
#define ARM_FUNC_START(name, gl) \
.align 3; \
.ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \
TYPE(name, %function); \
CNAME(name):
#define ARM_FUNC_END(name) \
SIZE(name)
/* Aid in defining a jump table with 8 bytes between entries. */
.macro E index
.if . - 0b - 8*\index
.error "type table out of sync"
.endif
.endm
.text
.syntax unified
.arm
/* We require interworking on LDM, which implies ARMv5T,
which implies the existance of BLX. */
.arch armv5t
/* Note that we use STC and LDC to encode VFP instructions,
so that we do not need ".fpu vfp", nor get that added to
the object file attributes. These will not be executed
unless the FFI_VFP abi is used. */
@ r0: stack
@ r1: frame
@ r2: fn
@ r3: vfp_used
ARM_FUNC_START(ffi_call_VFP, 1)
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 UNWIND .setfp fp, sp
cfi_def_cfa(fp, 8)
cfi_rel_offset(fp, 0)
cfi_rel_offset(lr, 4)
@ Make room for all of the new args. mov sp, r0 @ install the stack pointer
sub sp, fp, r2 mov lr, r2 @ move the fn pointer out of the way
ldr ip, [fp, #16] @ install the static chain
@ Place all of the ffi_prep_args in position ldmia sp!, {r0-r3} @ move first 4 parameters in registers.
mov r0, sp blx lr @ call fn
@ r1 already set
@ Call ffi_prep_args(stack, &ecif)
bl CNAME(ffi_prep_args_SYSV)
@ move first 4 parameters in registers
ldmia sp, {r0-r3}
@ and adjust stack
sub lr, fp, sp @ cif->bytes == fp - sp
ldr ip, [fp] @ load fn() in advance
cmp lr, #16
movhs lr, #16
add sp, sp, lr
@ 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 @ 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
#if defined(__SOFTFP__) || defined(__ARM_EABI__)
cmpne r3, #FFI_TYPE_DOUBLE
#endif
stmiaeq r2, {r0, r1}
#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
beq LSYM(Lepilogue)
@ return FLOAT
cmp r3, #FFI_TYPE_FLOAT
stfeqs f0, [r2]
beq LSYM(Lepilogue)
@ return DOUBLE or LONGDOUBLE
cmp r3, #FFI_TYPE_DOUBLE
stfeqd f0, [r2]
#endif
LSYM(Lepilogue):
#if defined (__INTERWORKING__)
ldmia sp!, {r0-r3,fp, lr}
bx lr
#else
ldmia sp!, {r0-r3,fp, pc}
#endif
.ffi_call_SYSV_end:
UNWIND .fnend UNWIND .fnend
#ifdef __ELF__ ARM_FUNC_END(ffi_call_SYSV)
.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]
add r1, sp, #8
bl CNAME(ffi_closure_inner)
cmp r0, #FFI_TYPE_INT
beq .Lretint
cmp r0, #FFI_TYPE_FLOAT /* See above. */
#if defined(__SOFTFP__) || defined(__ARM_EABI__) UNWIND .save {sp,lr}
beq .Lretint cfi_adjust_cfa_offset(8)
#else cfi_rel_offset(lr, 4)
beq .Lretfloat
#endif
cmp r0, #FFI_TYPE_DOUBLE add r3, sp, #8 @ load frame
#if defined(__SOFTFP__) || defined(__ARM_EABI__) bl CNAME(ffi_closure_inner_VFP)
beq .Lretlonglong
#else
beq .Lretdouble
#endif
cmp r0, #FFI_TYPE_LONGDOUBLE @ Load values returned in registers.
#if defined(__SOFTFP__) || defined(__ARM_EABI__) add r2, sp, #8+64 @ load result
beq .Lretlonglong adr r3, CNAME(ffi_closure_ret)
#else add pc, r3, r0, lsl #3
beq .Lretlongdouble cfi_endproc
#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 UNWIND .fnend
#ifdef __ELF__ ARM_FUNC_END(ffi_closure_VFP)
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
#endif
/* 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. */
/* Below are VFP hard-float ABI call and closure implementations. ARM_FUNC_START(ffi_closure_ret, 0)
Add VFP FPU directive here. This is only compiled into the library cfi_startproc
under EABI. */ cfi_rel_offset(sp, 0)
#ifdef __ARM_EABI__ cfi_rel_offset(lr, 4)
.fpu vfp 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)
@ r0: fn #if FFI_EXEC_TRAMPOLINE_TABLE
@ r1: &ecif
@ r2: cif->bytes
@ r3: fig->flags
@ sp+0: ecif.rvalue
ARM_FUNC_START(ffi_call_VFP) /* ??? The iOS support should be updated. The first insn used to
@ Save registers be STMFD, but that's been moved into ffi_closure_SYSV. If the
stmfd sp!, {r0-r3, fp, lr} writable page is put after this one we can make use of the
UNWIND .save {r0-r3, fp, lr} pc+8 feature of the architecture. We can also reduce the size
mov fp, sp of the thunk to 8 and pack more of these into the page.
UNWIND .setfp fp, sp
@ Make room for all of the new args. In the meantime, simply replace the STMFD with a NOP so as to
sub sp, sp, r2 keep all the magic numbers the same within ffi.c. */
@ Make room for loading VFP args .align 12
sub sp, sp, #64 ARM_FUNC_START(ffi_closure_trampoline_table_page)
.rept 4096 / 12
nop
ldr ip, [pc, #-4092]
ldr pc, [pc, #-4092]
.endr
@ Place all of the ffi_prep_args in position #else
mov r0, sp
@ r1 already set
sub r2, fp, #64 @ VFP scratch space
@ Call ffi_prep_args(stack, &ecif, vfp_space) ARM_FUNC_START(ffi_arm_trampoline, 1)
bl CNAME(ffi_prep_args_VFP) 0: adr ip, 0b
ldr pc, 1f
1: .long 0
ARM_FUNC_END(ffi_arm_trampoline)
@ Load VFP register args if needed #endif /* FFI_EXEC_TRAMPOLINE_TABLE */
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
-4450
View File
File diff suppressed because it is too large Load Diff
-11
View File
@@ -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)
+340 -553
View File
@@ -27,463 +27,304 @@
#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 # endif
) #else
{ # undef FFI_TYPE_LONGDOUBLE
*(unsigned int *) argp = (unsigned long)(* p_argv); # define FFI_TYPE_LONGDOUBLE 4
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 #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;
default:
abort();
}
cif->flags = flags;
bytes = 0;
for (i = 0, n = cif->nargs; i < n; ++i)
{
ffi_type *ty = cif->arg_types[i];
size_t z = ty->size;
int tt = ty->type;
switch (tt)
{
case FFI_TYPE_STRUCT:
case FFI_TYPE_LONGDOUBLE:
by_reference:
/* Passed by reference. */
z = 4;
break; break;
case FFI_TYPE_COMPLEX:
tt = ty->elements[0]->type;
if (tt == FFI_TYPE_FLOAT || z > 8)
goto by_reference;
/* FALLTHRU */
default: default:
cif->flags = FFI_TYPE_INT; z = ALIGN(z, 4);
break;
} }
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;
ffi_type **ptr = &arg->elements[0];
while (*ptr != NULL) int FFI_HIDDEN
ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
{ {
if (off & ((*ptr)->alignment - 1)) ffi_type **p_arg;
off = ALIGN(off, (*ptr)->alignment); int flags = cif->flags;
int i, nargs;
switch ((*ptr)->type) if (rvalue == NULL)
{
if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
{
/* 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;
}
}
/* 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++)
{
ffi_type *ty = p_arg[i];
void *a = avalue[i];
int tt = ty->type;
size_t z;
switch (tt)
{ {
case FFI_TYPE_STRUCT: case FFI_TYPE_STRUCT:
off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
off = ALIGN(off, FFI_SIZEOF_ARG);
break;
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
#endif by_reference:
memmove(ret + off, flt + off, (*ptr)->size); *argp++ = (unsigned long)a;
off += (*ptr)->size;
break; break;
case FFI_TYPE_DOUBLE:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
memcpy(argp, a, 8);
argp += 2;
break;
case FFI_TYPE_INT:
case FFI_TYPE_FLOAT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
*argp++ = *(unsigned *)a;
break;
case FFI_TYPE_UINT8:
*argp++ = *(UINT8 *)a;
break;
case FFI_TYPE_SINT8:
*argp++ = *(SINT8 *)a;
break;
case FFI_TYPE_UINT16:
*argp++ = *(UINT16 *)a;
break;
case FFI_TYPE_SINT16:
*argp++ = *(SINT16 *)a;
break;
case FFI_TYPE_COMPLEX:
tt = ty->elements[0]->type;
z = ty->size;
if (tt == FFI_TYPE_FLOAT || z > 8)
goto by_reference;
if (z < 4)
{
memcpy((char *)argp + 4 - z, a, z);
argp++;
}
else
{
memcpy(argp, a, z);
argp += z / 4;
}
break;
default: default:
memmove(ret + off, intg + off, (*ptr)->size); abort();
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
{
rval = NULL;
if (rvalue == NULL)
ecif.rvalue = alloca(cif->rtype->size);
} }
} }
switch (cif->abi) return flags;
}
static void
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
void **avalue, void *closure)
{ {
case FFI_V8: size_t bytes = cif->bytes;
#ifdef SPARC64
/* We don't yet support calling 32bit code from 64bit */ FFI_ASSERT (cif->abi == FFI_V8);
FFI_ASSERT(0);
#else /* If we've not got a return value, we need to create one if we've
if (rvalue && (cif->rtype->type == FFI_TYPE_STRUCT got to pass the return value to the callee. Otherwise ignore it. */
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE if (rvalue == NULL
|| cif->flags == FFI_TYPE_LONGDOUBLE && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
#endif 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)
{ {
/* For v8, we need an "unimp" with size of returning struct */ ffi_call_int (cif, fn, rvalue, avalue, NULL);
/* behind "call", so we alloc some executable space for it. */ }
/* l7 is used, we need to make sure v8.S doesn't use %l7. */
unsigned int *call_struct = NULL; void
ffi_closure_alloc(32, (void **)&call_struct); ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
if (call_struct) void **avalue, void *closure)
{ {
unsigned long f = (unsigned long)fn; ffi_call_int (cif, fn, rvalue, avalue, closure);
call_struct[0] = 0xae10001f; /* mov %i7, %l7 */ }
call_struct[1] = 0xbe10000f; /* mov %o7, %i7 */
call_struct[2] = 0x03000000 | f >> 10; /* sethi %hi(fn), %g1 */
call_struct[3] = 0x9fc06000 | (f & 0x3ff); /* jmp %g1+%lo(fn), %o7 */
call_struct[4] = 0x01000000; /* nop */
if (cif->rtype->size < 0x7f)
call_struct[5] = cif->rtype->size; /* unimp */
else
call_struct[5] = 0x01000000; /* nop */
call_struct[6] = 0x81c7e008; /* ret */
call_struct[7] = 0xbe100017; /* mov %l7, %i7 */
#ifdef __GNUC__ #ifdef __GNUC__
asm volatile ("iflush %0; iflush %0+8; iflush %0+16; iflush %0+24" : : static inline void
"r" (call_struct) : "memory"); ffi_flush_icache (void *p)
{
/* SPARC v8 requires 5 instructions for flush to be visible */ /* SPARC v8 requires 5 instructions for flush to be visible */
asm volatile ("nop; nop; nop; nop; nop"); asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop"
: : "r" (p) : "memory");
}
#else #else
ffi_flush_icache (call_struct, 32); extern void ffi_flush_icache (void *) FFI_HIDDEN;
#endif #endif
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
cif->flags, rvalue, call_struct);
ffi_closure_free(call_struct);
}
else
{
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
cif->flags, rvalue, fn);
}
}
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;
}
}
extern void ffi_closure_v8(void) FFI_HIDDEN;
#ifdef SPARC64 extern void ffi_go_closure_v8(void) FFI_HIDDEN;
extern void ffi_closure_v9(void);
#else
extern void ffi_closure_v8(void);
#endif
ffi_status ffi_status
ffi_prep_closure_loc (ffi_closure *closure, ffi_prep_closure_loc (ffi_closure *closure,
@@ -493,189 +334,135 @@ ffi_prep_closure_loc (ffi_closure* closure,
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;
} }
else argp++;
{ break;
/* Always right-justify. */
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; case FFI_TYPE_INT:
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; case FFI_TYPE_FLOAT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
break;
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
a += 2;
break;
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
a += 3;
break;
case FFI_TYPE_COMPLEX:
tt = ty->elements[0]->type;
z = ty->size;
if (tt == FFI_TYPE_FLOAT || z > 8)
goto by_reference;
if (z < 4)
a += 4 - z;
else if (z > 4)
argp++;
break;
default:
abort();
} }
argp++;
avalue[i] = a;
} }
/* Invoke the closure. */ /* 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 */
+592
View File
@@ -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 */
+9 -6
View File
@@ -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
+26
View File
@@ -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
+266 -251
View File
@@ -28,27 +28,33 @@
#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
@@ -56,148 +62,206 @@ _ffi_flush_icache:
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 nop
cmp %i3, FFI_TYPE_INT ! Note that each entry is 4 insns, enforced by the E macro.
be,a done .align 16
st %o0, [%i4] ! (delay) 2:
E SPARC_RET_VOID
cmp %i3, FFI_TYPE_FLOAT
be,a done
st %f0, [%i4+0] ! (delay)
cmp %i3, FFI_TYPE_DOUBLE
be,a double
st %f0, [%i4+0] ! (delay)
cmp %i3, FFI_TYPE_SINT8
be,a sint8
sll %o0, 24, %o0 ! (delay)
cmp %i3, FFI_TYPE_UINT8
be,a uint8
sll %o0, 24, %o0 ! (delay)
cmp %i3, FFI_TYPE_SINT16
be,a sint16
sll %o0, 16, %o0 ! (delay)
cmp %i3, FFI_TYPE_UINT16
be,a uint16
sll %o0, 16, %o0 ! (delay)
cmp %i3, FFI_TYPE_SINT64
be,a longlong
st %o0, [%i4+0] ! (delay)
done:
ret ret
restore restore
E SPARC_RET_STRUCT
double: unimp
st %f1, [%i4+4] E SPARC_RET_UINT8
and %o0, 0xff, %o0
st %o0, [%i2]
ret ret
restore restore
E SPARC_RET_SINT8
sint8: sll %o0, 24, %o0
b 7f
sra %o0, 24, %o0 sra %o0, 24, %o0
st %o0, [%i4+0] E SPARC_RET_UINT16
ret sll %o0, 16, %o0
restore b 7f
uint8:
srl %o0, 24, %o0
st %o0, [%i4+0]
ret
restore
sint16:
sra %o0, 16, %o0
st %o0, [%i4+0]
ret
restore
uint16:
srl %o0, 16, %o0 srl %o0, 16, %o0
st %o0, [%i4+0] 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
st %f6, [%i2+6*4]
nop
E SPARC_RET_F_6
st %f5, [%i2+5*4]
nop
st %f4, [%i2+4*4]
nop
E SPARC_RET_F_4
st %f3, [%i2+3*4]
nop
st %f2, [%i2+2*4]
nop
E SPARC_RET_F_2
st %f1, [%i2+4]
st %f0, [%i2]
ret
restore
E SP_V8_RET_CPLX8
stb %o0, [%i2+1]
b 10f
srl %o0, 8, %o0
E SPARC_RET_F_1
st %f0, [%i2]
ret ret
restore restore
longlong: .align 8
st %o1, [%i4+4] 9: sth %o0, [%i2]
ret
restore
.align 8
10: stb %o0, [%i2]
ret ret
restore restore
.LLFE1:
.ffi_call_v8_end: ! Struct returning functions expect and skip the unimp here.
.size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8 ! To make it worse, conforming callees examine the unimp and
! make sure the low 12 bits of the unimp match the size of
! the struct being returned.
.align 8
8: call 1f ! load pc in %o7
sll %l1, 2, %l0 ! size * 4
1: sll %l1, 4, %l1 ! size * 16
add %l0, %l1, %l0 ! size * 20
add %o7, %l0, %o7 ! o7 = 0b + size*20
jmp %o7+(2f-8b)
mov %i5, %g2 ! load static chain
2:
.rept 0x1000
call %i1
nop
unimp (. - 2b) / 20
ret
restore
.endr
cfi_endproc
.size C(ffi_call_v8),. - C(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
+278 -208
View File
@@ -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
+533 -771
View File
File diff suppressed because it is too large Load Diff
+230 -93
View File
@@ -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 0; /* Never reached. */ 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
}
}
}
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,23 +450,63 @@ 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]);
if (rtype_size == 4 && sse0)
flags = UNIX64_RET_XMM32;
else if (rtype_size == 8)
flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
else
{
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
if (sse0 && !sse1) if (sse0 && sse1)
flags |= 1 << 8; flags = UNIX64_RET_ST_XMM0_XMM1;
else if (!sse0 && sse1) else if (sse0)
flags |= 1 << 9; flags = UNIX64_RET_ST_XMM0_RAX;
else if (sse0 && sse1) else if (sse1)
flags |= 1 << 10; flags = UNIX64_RET_ST_RAX_XMM0;
/* Mark the true size of the structure. */ else
flags |= cif->rtype->size << 12; 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.
If it's in a register and there is space for it, let that be so. If If it's in a register and there is space for it, let that be so. If
@@ -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 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a); reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
break; break;
case FFI_TYPE_SINT16: case FFI_TYPE_SINT16:
*(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a); reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
break; break;
case FFI_TYPE_SINT32: case FFI_TYPE_SINT32:
*(SINT64 *)&reg_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 (&reg_args->gpr[gprcount], a, size < 8 ? size : 8); memcpy (&reg_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)
{
int abi = cif->abi;
if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
return FFI_BAD_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__ */
+32 -45
View File
@@ -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,30 +117,21 @@ 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) \
|| (defined (__x86_64__) && defined (X86_DARWIN))
# define FFI_TRAMPOLINE_SIZE 24 # define FFI_TRAMPOLINE_SIZE 24
# define FFI_NATIVE_RAW_API 0 # define FFI_NATIVE_RAW_API 0
#else #else
#ifdef X86_WIN32 # define FFI_TRAMPOLINE_SIZE 12
#define FFI_TRAMPOLINE_SIZE 52
#else
#ifdef X86_WIN64
#define FFI_TRAMPOLINE_SIZE 29
#define FFI_NATIVE_RAW_API 0
#define FFI_NO_RAW_API 1
#else
#define FFI_TRAMPOLINE_SIZE 10
#endif
#endif
#ifndef X86_WIN64
# define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
#endif #endif
#endif
#endif #endif
+281
View File
@@ -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 */
-463
View File
@@ -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
+23
View File
@@ -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
+22
View File
@@ -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
+624 -403
View File
File diff suppressed because it is too large Load Diff
+274 -296
View File
@@ -30,9 +30,22 @@
#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
.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 .align 2
.globl ffi_closure_unix64 .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
View File
File diff suppressed because it is too large Load Diff
+187 -488
View File
@@ -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
.macro E which
.align 8
.org 0b + \which * 8
.endm
.text .text
.extern SYMBOL_NAME(ffi_closure_win64_inner) /* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10)
# ffi_closure_win64 will be called with these registers set: Bit o trickiness here -- FRAME is the base of the stack frame
# rax points to 'closure' for this function. This has been allocated by ffi_call. We also
# r11 contains a bit mask that specifies which of the deallocate some of the stack that has been alloca'd. */
# 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: .align 8
test $2, %r11 .globl ffi_call_win64
jne .Lsecond_is_float
mov %rdx, 16(%rsp)
jmp .Lthird
.Lsecond_is_float:
movlpd %xmm1, 16(%rsp)
.Lthird: .seh_proc ffi_call_win64
test $4, %r11 ffi_call_win64:
jne .Lthird_is_float cfi_startproc
mov %r8,24(%rsp) /* Set up the local stack frame and install it in rbp/rsp. */
jmp .Lfourth movq (%rsp), %rax
.Lthird_is_float: movq %rbp, (arg1)
movlpd %xmm2, 24(%rsp) movq %rax, 8(arg1)
movq arg1, %rbp
.Lfourth: cfi_def_cfa(%rbp, 16)
test $8, %r11 cfi_rel_offset(%rbp, 0)
jne .Lfourth_is_float .seh_pushreg %rbp
mov %r9, 32(%rsp) .seh_setframe %rbp, 0
jmp .Ldone
.Lfourth_is_float:
movlpd %xmm3, 32(%rsp)
.Ldone:
.seh_stackalloc 40
sub $40, %rsp
.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
leaq SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax
callq *%rax # call the real closure function
add $40, %rsp
movq %rax, %xmm0 # If the closure returned a float,
# ffi_closure_win64_inner wrote it to rax
retq
.seh_endproc
.balign 16 movq arg2, %r10
.globl SYMBOL_NAME(ffi_call_win64)
.seh_proc SYMBOL_NAME(ffi_call_win64)
SYMBOL_NAME(ffi_call_win64):
# copy registers onto stack
mov %r9,32(%rsp)
mov %r8,24(%rsp)
mov %rdx,16(%rsp)
mov %rcx,8(%rsp)
.seh_pushreg rbp
push %rbp
.seh_stackalloc 48
sub $48,%rsp
.seh_setframe rbp, 32
lea 32(%rsp),%rbp
.seh_endprologue
mov CIF_BYTES(%rbp),%eax /* Load all slots into both general and xmm registers. */
add $15, %rax movq (%rsp), %rcx
and $-16, %rax movsd (%rsp), %xmm0
cmpq $0x1000, %rax movq 8(%rsp), %rdx
jb Lch_done movsd 8(%rsp), %xmm1
Lch_probe: movq 16(%rsp), %r8
subq $0x1000,%rsp movsd 16(%rsp), %xmm2
orl $0x0, (%rsp) movq 24(%rsp), %r9
subq $0x1000,%rax movsd 24(%rsp), %xmm3
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 call *16(%rbp)
mov STACK(%rbp), %rcx
callq *PREP_ARGS_FN(%rbp)
mov STACK(%rbp), %rsp 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
movlpd 24(%rsp), %xmm3 /* Below, we're space constrained most of the time. Thus we eschew the
movd %xmm3, %r9 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
movlpd 16(%rsp), %xmm2 .align 8
movd %xmm2, %r8 0:
E FFI_TYPE_VOID
movlpd 8(%rsp), %xmm1 epilogue
movd %xmm1, %rdx E FFI_TYPE_INT
movslq %eax, %rax
movlpd (%rsp), %xmm0 movq %rax, (%r8)
movd %xmm0, %rcx epilogue
E FFI_TYPE_FLOAT
callq *FN(%rbp) movss %xmm0, (%r8)
.Lret_struct4b: epilogue
cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp) E FFI_TYPE_DOUBLE
jne .Lret_struct2b movsd %xmm0, (%r8)
epilogue
mov RVALUE(%rbp), %rcx E FFI_TYPE_LONGDOUBLE
mov %eax, (%rcx) call abort
jmp .Lret_void E FFI_TYPE_UINT8
movzbl %al, %eax
.Lret_struct2b: movq %rax, (%r8)
cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp) epilogue
jne .Lret_struct1b E FFI_TYPE_SINT8
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 movsbq %al, %rax
movq %rax, (%rcx) jmp 98f
jmp .Lret_void E FFI_TYPE_UINT16
movzwl %ax, %eax
.Lret_uint16: movq %rax, (%r8)
cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp) epilogue
jne .Lret_sint16 E FFI_TYPE_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 movswq %ax, %rax
movq %rax, (%rcx) jmp 98f
jmp .Lret_void E FFI_TYPE_UINT32
.Lret_uint32:
cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
jne .Lret_sint32
mov RVALUE(%rbp), %rcx
movl %eax, %eax movl %eax, %eax
movq %rax, (%rcx) movq %rax, (%r8)
jmp .Lret_void 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
.Lret_sint32: .align 8
cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp) 99: call abort
jne .Lret_float
mov RVALUE(%rbp), %rcx .purgem epilogue
cltq
movq %rax, (%rcx)
jmp .Lret_void
.Lret_float: cfi_endproc
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 */
/* 32 bytes of outgoing register stack space, 8 bytes of alignment,
16 bytes of result, 32 bytes of xmm registers. */
#define ffi_clo_FS (32+8+16+32)
#define ffi_clo_OFF_R (32+8)
#define ffi_clo_OFF_X (32+8+16)
.align 8
.globl ffi_go_closure_win64
.seh_proc ffi_go_closure_win64
ffi_go_closure_win64:
cfi_startproc
/* Save all integer arguments into the incoming reg stack space. */
movq arg0, 8(%rsp)
movq arg1, 16(%rsp)
movq arg2, 24(%rsp)
movq arg3, 32(%rsp)
movq 8(%r10), arg0 /* load cif */
movq 16(%r10), arg1 /* load fun */
movq %r10, arg2 /* closure is user_data */
jmp 0f
cfi_endproc
.seh_endproc
.align 8
.globl ffi_closure_win64
.seh_proc ffi_closure_win64
ffi_closure_win64:
cfi_startproc
/* Save all integer arguments into the incoming reg stack space. */
movq arg0, 8(%rsp)
movq arg1, 16(%rsp)
movq arg2, 24(%rsp)
movq arg3, 32(%rsp)
movq FFI_TRAMPOLINE_SIZE(%r10), arg0 /* load cif */
movq FFI_TRAMPOLINE_SIZE+8(%r10), arg1 /* load fun */
movq FFI_TRAMPOLINE_SIZE+16(%r10), arg2 /* load user_data */
0:
subq $ffi_clo_FS, %rsp
cfi_adjust_cfa_offset(ffi_clo_FS)
.seh_stackalloc ffi_clo_FS
.seh_endprologue
/* Save all sse arguments into the stack frame. */
movsd %xmm0, ffi_clo_OFF_X(%rsp)
movsd %xmm1, ffi_clo_OFF_X+8(%rsp)
movsd %xmm2, ffi_clo_OFF_X+16(%rsp)
movsd %xmm3, ffi_clo_OFF_X+24(%rsp)
leaq ffi_clo_OFF_R(%rsp), arg3
call ffi_closure_win64_inner
/* Load the result into both possible result registers. */
movq ffi_clo_OFF_R(%rsp), %rax
movsd ffi_clo_OFF_R(%rsp), %xmm0
addq $ffi_clo_FS, %rsp
cfi_adjust_cfa_offset(-ffi_clo_FS)
ret
cfi_endproc
.seh_endproc
+11 -7
View File
@@ -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"
-2
View File
@@ -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"
+2 -2
View File
@@ -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;
} }
+1 -3
View File
@@ -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"
-2
View File
@@ -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"
+7 -3
View File
@@ -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);
} }
+1 -1
View File
@@ -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)