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