All these files live somewhere else now.
This commit is contained in:
@@ -1,101 +0,0 @@
|
|||||||
## Process this with automake to create Makefile.in
|
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = foreign
|
|
||||||
|
|
||||||
SUFFIXES = .c .lo .o .s .S
|
|
||||||
|
|
||||||
.deps/%.P: $(srcdir)/%.s
|
|
||||||
@echo "Computing dependencies for $<..."
|
|
||||||
@o='o'; \
|
|
||||||
test -n "$o" && o='$$o'; \
|
|
||||||
$(MKDEP) $< | sed "s,^\(.*\)\.o:,\1.$$o \1.l$$o $@:," > $@
|
|
||||||
|
|
||||||
.deps/%.P: $(srcdir)/%.S
|
|
||||||
@echo "Computing dependencies for $<..."
|
|
||||||
@o='o'; \
|
|
||||||
test -n "$o" && o='$$o'; \
|
|
||||||
$(MKDEP) $< | sed "s,^\(.*\)\.o:,\1.$$o \1.l$$o $@:," > $@
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libffi.la
|
|
||||||
noinst_PROGRAMS = ffitest
|
|
||||||
|
|
||||||
TARGET_SRC_MIPS_GCC = mips/ffi.c mips/o32.S mips/n32.S
|
|
||||||
TARGET_SRC_MIPS_SGI = mips/ffi.c mips/o32.s mips/n32.s
|
|
||||||
TARGET_SRC_X86 = x86/ffi.c x86/sysv.S
|
|
||||||
TARGET_SRC_SPARC = sparc/ffi.c sparc/v8.S
|
|
||||||
TARGET_SRC_ALPHA = alpha/ffi.c alpha/osf.S
|
|
||||||
TARGET_SRC_M68K = m68k/ffi.c m68k/sysv.S
|
|
||||||
TARGET_SRC_POWERPC = powerpc/ffi.c powerpc/sysv.S
|
|
||||||
TARGET_SRC_ARM = arm/sysv.S arm/ffi.c
|
|
||||||
TARGET_SRC_S390 = s390/sysv.S s390/ffi.c
|
|
||||||
|
|
||||||
##libffi_la_SOURCES = debug.c prep_cif.c types.c $(TARGET_SRC_@TARGET@)
|
|
||||||
## Work around automake deficiency
|
|
||||||
libffi_la_common_SOURCES = debug.c prep_cif.c types.c
|
|
||||||
if MIPS_GCC
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC)
|
|
||||||
endif
|
|
||||||
if MIPS_SGI
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_SGI)
|
|
||||||
endif
|
|
||||||
if X86
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_X86)
|
|
||||||
endif
|
|
||||||
if SPARC
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_SPARC)
|
|
||||||
endif
|
|
||||||
if ALPHA
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_ALPHA)
|
|
||||||
endif
|
|
||||||
if M68K
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_M68K)
|
|
||||||
endif
|
|
||||||
if POWERPC
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC)
|
|
||||||
endif
|
|
||||||
if ARM
|
|
||||||
libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
|
|
||||||
endif
|
|
||||||
|
|
||||||
libffi_la_LDFLAGS = -version-info 2:3:1
|
|
||||||
ffitest_SOURCES = ffitest.c
|
|
||||||
ffitest_LDADD = libffi.la
|
|
||||||
|
|
||||||
EXTRA_DIST = mips/ffi.c mips/n32.S mips/n32.s mips/o32.S mips/o32.s \
|
|
||||||
sparc/ffi.c sparc/v8.S \
|
|
||||||
x86/ffi.c x86/sysv.S \
|
|
||||||
alpha/ffi.c alpha/osf.S \
|
|
||||||
m68k/ffi.c m68k/sysv.S \
|
|
||||||
powerpc/ffi.c powerpc/sysv.S powerpc/asm.h \
|
|
||||||
arm/ffi.c arm/sysv.S
|
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/@TARGETDIR@
|
|
||||||
|
|
||||||
if MIPS_SGI
|
|
||||||
|
|
||||||
%.o: %.s
|
|
||||||
$(COMPILE) -c $<
|
|
||||||
|
|
||||||
# This rule should only be used for compiling with the SGI assembler.
|
|
||||||
%.lo: %.s
|
|
||||||
$(LTCOMPILE) -c $<
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
# This is the general rule.
|
|
||||||
%.o: %.S
|
|
||||||
$(COMPILE) -c $<
|
|
||||||
|
|
||||||
# This is the general rule.
|
|
||||||
%.lo: %.S
|
|
||||||
$(LTCOMPILE) -c $<
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/include -I../include
|
|
||||||
|
|
||||||
test: ffitest
|
|
||||||
./ffitest
|
|
||||||
|
|
||||||
lint:
|
|
||||||
$(LINT) $(INCLUDES) $(srcdir)/*.c $(srcdir)/@TARGETDIR@/*.c
|
|
||||||
@@ -1,428 +0,0 @@
|
|||||||
# Makefile.in generated automatically by automake 1.4a from Makefile.am
|
|
||||||
|
|
||||||
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
|
|
||||||
# This Makefile.in is free software; the Free Software Foundation
|
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
|
||||||
# with or without modifications, as long as this notice is preserved.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
|
||||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
# PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
SHELL = @SHELL@
|
|
||||||
|
|
||||||
srcdir = @srcdir@
|
|
||||||
top_srcdir = @top_srcdir@
|
|
||||||
prefix = @prefix@
|
|
||||||
exec_prefix = @exec_prefix@
|
|
||||||
|
|
||||||
bindir = @bindir@
|
|
||||||
sbindir = @sbindir@
|
|
||||||
libexecdir = @libexecdir@
|
|
||||||
datadir = @datadir@
|
|
||||||
sysconfdir = @sysconfdir@
|
|
||||||
sharedstatedir = @sharedstatedir@
|
|
||||||
localstatedir = @localstatedir@
|
|
||||||
libdir = @libdir@
|
|
||||||
infodir = @infodir@
|
|
||||||
mandir = @mandir@
|
|
||||||
includedir = @includedir@
|
|
||||||
oldincludedir = /usr/include
|
|
||||||
|
|
||||||
DESTDIR =
|
|
||||||
|
|
||||||
pkgdatadir = $(datadir)/@PACKAGE@
|
|
||||||
pkglibdir = $(libdir)/@PACKAGE@
|
|
||||||
pkgincludedir = $(includedir)/@PACKAGE@
|
|
||||||
|
|
||||||
top_builddir = ..
|
|
||||||
|
|
||||||
ACLOCAL = @ACLOCAL@
|
|
||||||
AUTOCONF = @AUTOCONF@
|
|
||||||
AUTOMAKE = @AUTOMAKE@
|
|
||||||
AUTOHEADER = @AUTOHEADER@
|
|
||||||
|
|
||||||
INSTALL = @INSTALL@
|
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
|
||||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
|
||||||
INSTALL_STRIP_FLAG =
|
|
||||||
transform = @program_transform_name@
|
|
||||||
|
|
||||||
NORMAL_INSTALL = :
|
|
||||||
PRE_INSTALL = :
|
|
||||||
POST_INSTALL = :
|
|
||||||
NORMAL_UNINSTALL = :
|
|
||||||
PRE_UNINSTALL = :
|
|
||||||
POST_UNINSTALL = :
|
|
||||||
host_alias = @host_alias@
|
|
||||||
host_triplet = @host@
|
|
||||||
AMTAR = @AMTAR@
|
|
||||||
AMTARFLAGS = @AMTARFLAGS@
|
|
||||||
AS = @AS@
|
|
||||||
CC = @CC@
|
|
||||||
DLLTOOL = @DLLTOOL@
|
|
||||||
EXEEXT = @EXEEXT@
|
|
||||||
LD = @LD@
|
|
||||||
LIBTOOL = @LIBTOOL@
|
|
||||||
LN_S = @LN_S@
|
|
||||||
MAINT = @MAINT@
|
|
||||||
MAKEINFO = @MAKEINFO@
|
|
||||||
NM = @NM@
|
|
||||||
PACKAGE = @PACKAGE@
|
|
||||||
RANLIB = @RANLIB@
|
|
||||||
SHELL = @SHELL@
|
|
||||||
TARGET = @TARGET@
|
|
||||||
TARGETDIR = @TARGETDIR@
|
|
||||||
USE_SYMBOL_UNDERSCORE = @USE_SYMBOL_UNDERSCORE@
|
|
||||||
VERSION = @VERSION@
|
|
||||||
|
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = foreign
|
|
||||||
|
|
||||||
SUFFIXES = .c .lo .o .s .S
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libffi.la
|
|
||||||
noinst_PROGRAMS = ffitest
|
|
||||||
|
|
||||||
TARGET_SRC_MIPS_GCC = mips/ffi.c mips/o32.S mips/n32.S
|
|
||||||
TARGET_SRC_MIPS_SGI = mips/ffi.c mips/o32.s mips/n32.s
|
|
||||||
TARGET_SRC_X86 = x86/ffi.c x86/sysv.S
|
|
||||||
TARGET_SRC_SPARC = sparc/ffi.c sparc/v8.S
|
|
||||||
TARGET_SRC_ALPHA = alpha/ffi.c alpha/osf.S
|
|
||||||
TARGET_SRC_M68K = m68k/ffi.c m68k/sysv.S
|
|
||||||
TARGET_SRC_POWERPC = powerpc/ffi.c powerpc/sysv.S
|
|
||||||
TARGET_SRC_ARM = arm/sysv.S arm/ffi.c
|
|
||||||
|
|
||||||
libffi_la_common_SOURCES = debug.c prep_cif.c types.c
|
|
||||||
@MIPS_GCC_TRUE@libffi_la_SOURCES = @MIPS_GCC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC)
|
|
||||||
@MIPS_SGI_TRUE@libffi_la_SOURCES = @MIPS_SGI_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_SGI)
|
|
||||||
@X86_TRUE@libffi_la_SOURCES = @X86_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86)
|
|
||||||
@SPARC_TRUE@libffi_la_SOURCES = @SPARC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_SPARC)
|
|
||||||
@ALPHA_TRUE@libffi_la_SOURCES = @ALPHA_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ALPHA)
|
|
||||||
@M68K_TRUE@libffi_la_SOURCES = @M68K_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_M68K)
|
|
||||||
@POWERPC_TRUE@libffi_la_SOURCES = @POWERPC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC)
|
|
||||||
@ARM_TRUE@libffi_la_SOURCES = @ARM_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
|
|
||||||
|
|
||||||
libffi_la_LDFLAGS = -version-info 2:3:1
|
|
||||||
ffitest_SOURCES = ffitest.c
|
|
||||||
ffitest_LDADD = libffi.la
|
|
||||||
|
|
||||||
EXTRA_DIST = mips/ffi.c mips/n32.S mips/n32.s mips/o32.S mips/o32.s \
|
|
||||||
sparc/ffi.c sparc/v8.S \
|
|
||||||
x86/ffi.c x86/sysv.S \
|
|
||||||
alpha/ffi.c alpha/osf.S \
|
|
||||||
m68k/ffi.c m68k/sysv.S \
|
|
||||||
powerpc/ffi.c powerpc/sysv.S powerpc/asm.h \
|
|
||||||
arm/ffi.c arm/sysv.S
|
|
||||||
|
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/@TARGETDIR@
|
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/include -I../include
|
|
||||||
subdir = src
|
|
||||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
|
||||||
CONFIG_HEADER = ../fficonfig.h
|
|
||||||
CONFIG_CLEAN_FILES =
|
|
||||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
|
||||||
|
|
||||||
|
|
||||||
DEFS = @DEFS@ -I. -I$(srcdir) -I..
|
|
||||||
CPPFLAGS = @CPPFLAGS@
|
|
||||||
LDFLAGS = @LDFLAGS@
|
|
||||||
LIBS = @LIBS@
|
|
||||||
libffi_la_LIBADD =
|
|
||||||
@ALPHA_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
|
|
||||||
@ALPHA_TRUE@osf.lo
|
|
||||||
@ARM_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo sysv.lo \
|
|
||||||
@ARM_TRUE@ffi.lo
|
|
||||||
@M68K_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
|
|
||||||
@M68K_TRUE@sysv.lo
|
|
||||||
@MIPS_GCC_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo \
|
|
||||||
@MIPS_GCC_TRUE@ffi.lo o32.lo n32.lo
|
|
||||||
@MIPS_SGI_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo \
|
|
||||||
@MIPS_SGI_TRUE@ffi.lo o32.lo n32.lo
|
|
||||||
@POWERPC_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo \
|
|
||||||
@POWERPC_TRUE@ffi.lo sysv.lo
|
|
||||||
@SPARC_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
|
|
||||||
@SPARC_TRUE@v8.lo
|
|
||||||
@X86_TRUE@am_libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
|
|
||||||
@X86_TRUE@sysv.lo
|
|
||||||
libffi_la_OBJECTS = $(am_libffi_la_OBJECTS)
|
|
||||||
noinst_PROGRAMS = ffitest$(EXEEXT)
|
|
||||||
PROGRAMS = $(noinst_PROGRAMS)
|
|
||||||
|
|
||||||
am_ffitest_OBJECTS = ffitest.o
|
|
||||||
ffitest_OBJECTS = $(am_ffitest_OBJECTS)
|
|
||||||
ffitest_DEPENDENCIES = libffi.la
|
|
||||||
ffitest_LDFLAGS =
|
|
||||||
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
|
||||||
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
|
||||||
CFLAGS = @CFLAGS@
|
|
||||||
CCLD = $(CC)
|
|
||||||
LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
|
||||||
DIST_SOURCES = $(libffi_la_SOURCES) $(ffitest_SOURCES)
|
|
||||||
DIST_COMMON = Makefile.am Makefile.in
|
|
||||||
|
|
||||||
|
|
||||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
|
||||||
|
|
||||||
GZIP_ENV = --best
|
|
||||||
SOURCES = $(libffi_la_SOURCES) $(ffitest_SOURCES)
|
|
||||||
OBJECTS = $(am_libffi_la_OBJECTS) $(am_ffitest_OBJECTS)
|
|
||||||
|
|
||||||
all: all-redirect
|
|
||||||
.SUFFIXES:
|
|
||||||
.SUFFIXES: .S .c .lo .o .s
|
|
||||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
|
|
||||||
cd $(top_srcdir) && $(AUTOMAKE) --cygnus src/Makefile
|
|
||||||
|
|
||||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
|
||||||
cd $(top_builddir) \
|
|
||||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
|
||||||
|
|
||||||
|
|
||||||
mostlyclean-libLTLIBRARIES:
|
|
||||||
|
|
||||||
clean-libLTLIBRARIES:
|
|
||||||
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
|
||||||
|
|
||||||
distclean-libLTLIBRARIES:
|
|
||||||
|
|
||||||
maintainer-clean-libLTLIBRARIES:
|
|
||||||
|
|
||||||
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
|
||||||
@$(NORMAL_INSTALL)
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$(libdir)
|
|
||||||
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
|
||||||
if test -f $$p; then \
|
|
||||||
echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \
|
|
||||||
$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \
|
|
||||||
else :; fi; \
|
|
||||||
done
|
|
||||||
|
|
||||||
uninstall-libLTLIBRARIES:
|
|
||||||
@$(NORMAL_UNINSTALL)
|
|
||||||
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
|
||||||
echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \
|
|
||||||
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
|
|
||||||
done
|
|
||||||
|
|
||||||
mostlyclean-compile:
|
|
||||||
-rm -f *.o core *.core
|
|
||||||
|
|
||||||
clean-compile:
|
|
||||||
|
|
||||||
distclean-compile:
|
|
||||||
-rm -f *.tab.c
|
|
||||||
|
|
||||||
maintainer-clean-compile:
|
|
||||||
|
|
||||||
mostlyclean-libtool:
|
|
||||||
-rm -f *.lo
|
|
||||||
|
|
||||||
clean-libtool:
|
|
||||||
-rm -rf .libs _libs
|
|
||||||
|
|
||||||
distclean-libtool:
|
|
||||||
|
|
||||||
maintainer-clean-libtool:
|
|
||||||
ffi.lo: alpha/ffi.c
|
|
||||||
osf.lo: alpha/osf.S
|
|
||||||
sysv.lo: arm/sysv.S
|
|
||||||
o32.lo: mips/o32.S
|
|
||||||
n32.lo: mips/n32.S
|
|
||||||
v8.lo: sparc/v8.S
|
|
||||||
|
|
||||||
libffi.la: $(libffi_la_OBJECTS) $(libffi_la_DEPENDENCIES)
|
|
||||||
$(LINK) -rpath $(libdir) $(libffi_la_LDFLAGS) $(libffi_la_OBJECTS) $(libffi_la_LIBADD) $(LIBS)
|
|
||||||
|
|
||||||
mostlyclean-noinstPROGRAMS:
|
|
||||||
|
|
||||||
clean-noinstPROGRAMS:
|
|
||||||
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
|
|
||||||
|
|
||||||
distclean-noinstPROGRAMS:
|
|
||||||
|
|
||||||
maintainer-clean-noinstPROGRAMS:
|
|
||||||
|
|
||||||
ffitest$(EXEEXT): $(ffitest_OBJECTS) $(ffitest_DEPENDENCIES)
|
|
||||||
@rm -f ffitest$(EXEEXT)
|
|
||||||
$(LINK) $(ffitest_LDFLAGS) $(ffitest_OBJECTS) $(ffitest_LDADD) $(LIBS)
|
|
||||||
.S.o:
|
|
||||||
$(COMPILE) -c $<
|
|
||||||
.S.lo:
|
|
||||||
$(LTCOMPILE) -c -o $@ $<
|
|
||||||
.c.o:
|
|
||||||
$(COMPILE) -c $<
|
|
||||||
.c.lo:
|
|
||||||
$(LTCOMPILE) -c -o $@ $<
|
|
||||||
.s.o:
|
|
||||||
$(COMPILE) -c $<
|
|
||||||
.s.lo:
|
|
||||||
$(LTCOMPILE) -c -o $@ $<
|
|
||||||
|
|
||||||
tags: TAGS
|
|
||||||
|
|
||||||
ID: $(HEADERS) $(SOURCES) $(LISP)
|
|
||||||
list='$(SOURCES) $(HEADERS)'; \
|
|
||||||
unique=`for i in $$list; do echo $$i; done | \
|
|
||||||
awk ' { files[$$0] = 1; } \
|
|
||||||
END { for (i in files) print i; }'`; \
|
|
||||||
here=`pwd` && cd $(srcdir) \
|
|
||||||
&& mkid -f$$here/ID $$unique $(LISP)
|
|
||||||
|
|
||||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
|
|
||||||
tags=; \
|
|
||||||
here=`pwd`; \
|
|
||||||
list='$(SOURCES) $(HEADERS)'; \
|
|
||||||
unique=`for i in $$list; do echo $$i; done | \
|
|
||||||
awk ' { files[$$0] = 1; } \
|
|
||||||
END { for (i in files) print i; }'`; \
|
|
||||||
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|
|
||||||
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
|
|
||||||
|
|
||||||
mostlyclean-tags:
|
|
||||||
|
|
||||||
clean-tags:
|
|
||||||
|
|
||||||
distclean-tags:
|
|
||||||
-rm -f TAGS ID
|
|
||||||
|
|
||||||
maintainer-clean-tags:
|
|
||||||
|
|
||||||
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
|
|
||||||
|
|
||||||
distdir: $(DISTFILES)
|
|
||||||
$(mkinstalldirs) $(distdir)/alpha $(distdir)/arm $(distdir)/m68k \
|
|
||||||
$(distdir)/mips $(distdir)/powerpc $(distdir)/sparc \
|
|
||||||
$(distdir)/x86
|
|
||||||
@for file in $(DISTFILES); do \
|
|
||||||
if test -f $$file; then d=.; else d=$(srcdir); fi; \
|
|
||||||
if test -d $$d/$$file; then \
|
|
||||||
cp -pr $$d/$$file $(distdir)/$$file; \
|
|
||||||
else \
|
|
||||||
test -f $(distdir)/$$file \
|
|
||||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
|
||||||
|| cp -p $$d/$$file $(distdir)/$$file || :; \
|
|
||||||
fi; \
|
|
||||||
done
|
|
||||||
info-am:
|
|
||||||
info: info-am
|
|
||||||
dvi-am:
|
|
||||||
dvi: dvi-am
|
|
||||||
check-am:
|
|
||||||
check: check-am
|
|
||||||
installcheck-am:
|
|
||||||
installcheck: installcheck-am
|
|
||||||
install-info-am:
|
|
||||||
install-info: install-info-am
|
|
||||||
install-exec-am: install-libLTLIBRARIES
|
|
||||||
install-exec: install-exec-am
|
|
||||||
|
|
||||||
install-data-am:
|
|
||||||
install-data: install-data-am
|
|
||||||
|
|
||||||
install-am: all-am
|
|
||||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
|
||||||
install: install-am
|
|
||||||
uninstall-am: uninstall-libLTLIBRARIES
|
|
||||||
uninstall: uninstall-am
|
|
||||||
all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
|
|
||||||
all-redirect: all-am
|
|
||||||
install-strip:
|
|
||||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
|
|
||||||
installdirs:
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$(libdir)
|
|
||||||
|
|
||||||
|
|
||||||
mostlyclean-generic:
|
|
||||||
|
|
||||||
clean-generic:
|
|
||||||
|
|
||||||
distclean-generic:
|
|
||||||
-rm -f Makefile $(CONFIG_CLEAN_FILES)
|
|
||||||
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
|
|
||||||
|
|
||||||
maintainer-clean-generic:
|
|
||||||
mostlyclean-am: mostlyclean-libLTLIBRARIES mostlyclean-compile \
|
|
||||||
mostlyclean-libtool mostlyclean-noinstPROGRAMS \
|
|
||||||
mostlyclean-tags mostlyclean-generic
|
|
||||||
|
|
||||||
mostlyclean: mostlyclean-am
|
|
||||||
|
|
||||||
clean-am: clean-libLTLIBRARIES clean-compile clean-libtool \
|
|
||||||
clean-noinstPROGRAMS clean-tags clean-generic \
|
|
||||||
mostlyclean-am
|
|
||||||
|
|
||||||
clean: clean-am
|
|
||||||
|
|
||||||
distclean-am: distclean-libLTLIBRARIES distclean-compile \
|
|
||||||
distclean-libtool distclean-noinstPROGRAMS \
|
|
||||||
distclean-tags distclean-generic clean-am
|
|
||||||
-rm -f libtool
|
|
||||||
|
|
||||||
distclean: distclean-am
|
|
||||||
|
|
||||||
maintainer-clean-am: maintainer-clean-libLTLIBRARIES \
|
|
||||||
maintainer-clean-compile maintainer-clean-libtool \
|
|
||||||
maintainer-clean-noinstPROGRAMS maintainer-clean-tags \
|
|
||||||
maintainer-clean-generic distclean-am
|
|
||||||
@echo "This command is intended for maintainers to use;"
|
|
||||||
@echo "it deletes files that may require special tools to rebuild."
|
|
||||||
|
|
||||||
maintainer-clean: maintainer-clean-am
|
|
||||||
|
|
||||||
.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \
|
|
||||||
clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \
|
|
||||||
uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \
|
|
||||||
distclean-compile clean-compile maintainer-clean-compile \
|
|
||||||
mostlyclean-libtool distclean-libtool clean-libtool \
|
|
||||||
maintainer-clean-libtool mostlyclean-noinstPROGRAMS \
|
|
||||||
distclean-noinstPROGRAMS clean-noinstPROGRAMS \
|
|
||||||
maintainer-clean-noinstPROGRAMS tags mostlyclean-tags distclean-tags \
|
|
||||||
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
|
|
||||||
check-am installcheck-am installcheck install-info-am install-info \
|
|
||||||
install-exec-am install-exec install-data-am install-data install-am \
|
|
||||||
install uninstall-am uninstall all-redirect all-am all install-strip \
|
|
||||||
installdirs mostlyclean-generic distclean-generic clean-generic \
|
|
||||||
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
|
|
||||||
|
|
||||||
|
|
||||||
.deps/%.P: $(srcdir)/%.s
|
|
||||||
@echo "Computing dependencies for $<..."
|
|
||||||
@o='o'; \
|
|
||||||
test -n "$o" && o='$$o'; \
|
|
||||||
$(MKDEP) $< | sed "s,^\(.*\)\.o:,\1.$$o \1.l$$o $@:," > $@
|
|
||||||
|
|
||||||
.deps/%.P: $(srcdir)/%.S
|
|
||||||
@echo "Computing dependencies for $<..."
|
|
||||||
@o='o'; \
|
|
||||||
test -n "$o" && o='$$o'; \
|
|
||||||
$(MKDEP) $< | sed "s,^\(.*\)\.o:,\1.$$o \1.l$$o $@:," > $@
|
|
||||||
|
|
||||||
@MIPS_SGI_TRUE@%.o: %.s
|
|
||||||
@MIPS_SGI_TRUE@ $(COMPILE) -c $<
|
|
||||||
|
|
||||||
# This rule should only be used for compiling with the SGI assembler.
|
|
||||||
@MIPS_SGI_TRUE@%.lo: %.s
|
|
||||||
@MIPS_SGI_TRUE@ $(LTCOMPILE) -c $<
|
|
||||||
|
|
||||||
# This is the general rule.
|
|
||||||
@MIPS_SGI_FALSE@%.o: %.S
|
|
||||||
@MIPS_SGI_FALSE@ $(COMPILE) -c $<
|
|
||||||
|
|
||||||
# This is the general rule.
|
|
||||||
@MIPS_SGI_FALSE@%.lo: %.S
|
|
||||||
@MIPS_SGI_FALSE@ $(LTCOMPILE) -c $<
|
|
||||||
|
|
||||||
test: ffitest
|
|
||||||
./ffitest
|
|
||||||
|
|
||||||
lint:
|
|
||||||
$(LINT) $(INCLUDES) $(srcdir)/*.c $(srcdir)/@TARGETDIR@/*.c
|
|
||||||
|
|
||||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
|
||||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
|
||||||
.NOEXPORT:
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
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
|
|
||||||
``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 CYGNUS SOLUTIONS 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>
|
|
||||||
|
|
||||||
extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
|
|
||||||
extern void ffi_closure_osf(void);
|
|
||||||
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
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*SIZEOF_ARG)
|
|
||||||
cif->bytes = 6*SIZEOF_ARG;
|
|
||||||
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags = cif->rtype->type;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
cif->flags = FFI_TYPE_INT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
|
|
||||||
{
|
|
||||||
unsigned long *stack, *argp;
|
|
||||||
long i, avn;
|
|
||||||
ffi_type **arg_types;
|
|
||||||
|
|
||||||
FFI_ASSERT (cif->abi == FFI_OSF);
|
|
||||||
|
|
||||||
/* If the return value is a struct and we don't have a return
|
|
||||||
value address then we need to make one. */
|
|
||||||
if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT)
|
|
||||||
rvalue = alloca(cif->rtype->size);
|
|
||||||
|
|
||||||
/* Allocate the space for the arguments, plus 4 words of temp
|
|
||||||
space for ffi_call_osf. */
|
|
||||||
argp = stack = alloca(cif->bytes + 4*SIZEOF_ARG);
|
|
||||||
|
|
||||||
if (cif->flags == FFI_TYPE_STRUCT)
|
|
||||||
*(void **) argp++ = rvalue;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
avn = cif->nargs;
|
|
||||||
arg_types = cif->arg_types;
|
|
||||||
|
|
||||||
while (i < avn)
|
|
||||||
{
|
|
||||||
switch ((*arg_types)->type)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
memcpy(argp, *avalue, (*arg_types)->size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
argp += ALIGN((*arg_types)->size, SIZEOF_ARG) / SIZEOF_ARG;
|
|
||||||
i++, arg_types++, avalue++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_closure (ffi_closure* closure,
|
|
||||||
ffi_cif* cif,
|
|
||||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
unsigned int *tramp;
|
|
||||||
|
|
||||||
FFI_ASSERT (cif->abi == FFI_OSF);
|
|
||||||
|
|
||||||
tramp = (unsigned int *) &closure->tramp[0];
|
|
||||||
tramp[0] = 0x47fb0401; /* mov $27,$1 */
|
|
||||||
tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
|
|
||||||
tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
|
|
||||||
tramp[3] = 0x47ff041f; /* nop */
|
|
||||||
*(void **) &tramp[4] = ffi_closure_osf;
|
|
||||||
|
|
||||||
closure->cif = cif;
|
|
||||||
closure->fun = fun;
|
|
||||||
closure->user_data = user_data;
|
|
||||||
|
|
||||||
/* Flush the Icache. */
|
|
||||||
asm volatile ("imb" : : : "memory");
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
|
|
||||||
{
|
|
||||||
ffi_cif *cif;
|
|
||||||
void **avalue;
|
|
||||||
ffi_type **arg_types;
|
|
||||||
long i, avn, argn;
|
|
||||||
|
|
||||||
cif = closure->cif;
|
|
||||||
avalue = alloca(cif->nargs * sizeof(void *));
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
switch (arg_types[i]->type)
|
|
||||||
{
|
|
||||||
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_STRUCT:
|
|
||||||
avalue[i] = &argp[argn];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
avalue[i] = &argp[argn];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invoke the closure. */
|
|
||||||
(closure->fun) (cif, rvalue, avalue, closure->user_data);
|
|
||||||
|
|
||||||
/* Tell ffi_closure_osf how to perform return type promotions. */
|
|
||||||
return cif->rtype->type;
|
|
||||||
}
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
osf.S - Copyright (c) 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
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
|
|
||||||
``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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
.arch ev6
|
|
||||||
.text
|
|
||||||
|
|
||||||
/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
|
|
||||||
void *raddr, void (*fnaddr)());
|
|
||||||
|
|
||||||
Bit o trickiness here -- ARGS+BYTES 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
|
|
||||||
.globl ffi_call_osf
|
|
||||||
.ent ffi_call_osf
|
|
||||||
ffi_call_osf:
|
|
||||||
.frame $15, 32, $26, 0
|
|
||||||
.mask 0x4008000, -32
|
|
||||||
addq $16,$17,$1
|
|
||||||
mov $16, $30
|
|
||||||
stq $26, 0($1)
|
|
||||||
stq $15, 8($1)
|
|
||||||
stq $18, 16($1)
|
|
||||||
mov $1, $15
|
|
||||||
.prologue 0
|
|
||||||
|
|
||||||
stq $19, 24($1)
|
|
||||||
mov $20, $27
|
|
||||||
|
|
||||||
# Load up all of the (potential) argument registers.
|
|
||||||
ldq $16, 0($30)
|
|
||||||
ldt $f16, 0($30)
|
|
||||||
ldt $f17, 8($30)
|
|
||||||
ldq $17, 8($30)
|
|
||||||
ldt $f18, 16($30)
|
|
||||||
ldq $18, 16($30)
|
|
||||||
ldt $f19, 24($30)
|
|
||||||
ldq $19, 24($30)
|
|
||||||
ldt $f20, 32($30)
|
|
||||||
ldq $20, 32($30)
|
|
||||||
ldt $f21, 40($30)
|
|
||||||
ldq $21, 40($30)
|
|
||||||
|
|
||||||
# Deallocate the register argument area.
|
|
||||||
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)
|
|
||||||
ldq $26, 0($15)
|
|
||||||
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
|
|
||||||
|
|
||||||
$noretval:
|
|
||||||
ldq $15, 8($15)
|
|
||||||
ret
|
|
||||||
|
|
||||||
$retint:
|
|
||||||
stq $0, 0($19)
|
|
||||||
nop
|
|
||||||
ldq $15, 8($15)
|
|
||||||
ret
|
|
||||||
|
|
||||||
$retfloat:
|
|
||||||
sts $f0, 0($19)
|
|
||||||
nop
|
|
||||||
ldq $15, 8($15)
|
|
||||||
ret
|
|
||||||
|
|
||||||
$retdouble:
|
|
||||||
stt $f0, 0($19)
|
|
||||||
nop
|
|
||||||
ldq $15, 8($15)
|
|
||||||
ret
|
|
||||||
|
|
||||||
.end ffi_call_osf
|
|
||||||
|
|
||||||
/* ffi_closure_osf(...)
|
|
||||||
|
|
||||||
Receives the closure argument in $1. */
|
|
||||||
|
|
||||||
.align 3
|
|
||||||
.globl ffi_closure_osf
|
|
||||||
.ent ffi_closure_osf
|
|
||||||
ffi_closure_osf:
|
|
||||||
.frame $30, 16*8, $26, 0
|
|
||||||
.mask 0x4000000, -16*8
|
|
||||||
ldgp $29, 0($27)
|
|
||||||
subq $30, 16*8, $30
|
|
||||||
stq $26, 0($30)
|
|
||||||
.prologue 1
|
|
||||||
|
|
||||||
# Store all of the potential argument registers in va_list format.
|
|
||||||
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)
|
|
||||||
jsr $26, ffi_closure_osf_inner
|
|
||||||
ldgp $29, 0($26)
|
|
||||||
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
|
|
||||||
jmp $31, ($1), $load_32
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
$load_none:
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
$load_float:
|
|
||||||
lds $f0, 16($30)
|
|
||||||
nop
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
$load_double:
|
|
||||||
ldt $f0, 16($30)
|
|
||||||
nop
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.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
|
|
||||||
|
|
||||||
.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)
|
|
||||||
zapnot $0, 3, $0
|
|
||||||
#endif
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
$load_s16:
|
|
||||||
#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
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
$load_32:
|
|
||||||
ldl $0, 16($30)
|
|
||||||
nop
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
$load_64:
|
|
||||||
ldq $0, 16($30)
|
|
||||||
nop
|
|
||||||
addq $30, 16*8, $30
|
|
||||||
ret
|
|
||||||
|
|
||||||
.end ffi_closure_osf
|
|
||||||
|
|
||||||
.section .rodata
|
|
||||||
$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_double # FFI_TYPE_LONGDOUBLE
|
|
||||||
.gprel32 $load_u8 # FFI_TYPE_UINT8
|
|
||||||
.gprel32 $load_s8 # FFI_TYPE_SINT8
|
|
||||||
.gprel32 $load_u16 # FFI_TYPE_UINT16
|
|
||||||
.gprel32 $load_s16 # FFI_TYPE_SINT16
|
|
||||||
.gprel32 $load_32 # FFI_TYPE_UINT32
|
|
||||||
.gprel32 $load_32 # FFI_TYPE_SINT32
|
|
||||||
.gprel32 $load_64 # FFI_TYPE_UINT64
|
|
||||||
.gprel32 $load_64 # FFI_TYPE_SINT64
|
|
||||||
.gprel32 $load_none # FFI_TYPE_STRUCT
|
|
||||||
.gprel32 $load_64 # FFI_TYPE_POINTER
|
|
||||||
|
|
||||||
/* Assert that the table above is in sync with ffi.h. */
|
|
||||||
|
|
||||||
#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
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
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
|
|
||||||
``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 CYGNUS SOLUTIONS 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>
|
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space
|
|
||||||
has been allocated for the function's arguments */
|
|
||||||
|
|
||||||
/*@-exportheader@*/
|
|
||||||
void ffi_prep_args(char *stack, extended_cif *ecif)
|
|
||||||
/*@=exportheader@*/
|
|
||||||
{
|
|
||||||
register unsigned int i;
|
|
||||||
register int tmp;
|
|
||||||
register unsigned int avn;
|
|
||||||
register void **p_argv;
|
|
||||||
register char *argp;
|
|
||||||
register ffi_type **p_arg;
|
|
||||||
|
|
||||||
tmp = 0;
|
|
||||||
argp = stack;
|
|
||||||
|
|
||||||
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) {
|
|
||||||
*(void **) argp = ecif->rvalue;
|
|
||||||
argp += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
avn = ecif->cif->nargs;
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
|
|
||||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
|
||||||
(i != 0) && (avn != 0);
|
|
||||||
i--, p_arg++)
|
|
||||||
{
|
|
||||||
size_t z;
|
|
||||||
|
|
||||||
/* Align if necessary */
|
|
||||||
if (((*p_arg)->alignment - 1) & (unsigned) argp) {
|
|
||||||
argp = (char *) ALIGN(argp, (*p_arg)->alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avn != 0)
|
|
||||||
{
|
|
||||||
avn--;
|
|
||||||
z = (*p_arg)->size;
|
|
||||||
if (z < sizeof(int))
|
|
||||||
{
|
|
||||||
z = sizeof(int);
|
|
||||||
switch ((*p_arg)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (z == sizeof(int))
|
|
||||||
{
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(argp, *p_argv, z);
|
|
||||||
}
|
|
||||||
p_argv++;
|
|
||||||
argp += z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|
||||||
{
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags = (unsigned) cif->rtype->type;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
cif->flags = FFI_TYPE_INT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*@-declundef@*/
|
|
||||||
/*@-exportheader@*/
|
|
||||||
extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
|
|
||||||
/*@out@*/ extended_cif *,
|
|
||||||
unsigned, unsigned,
|
|
||||||
/*@out@*/ unsigned *,
|
|
||||||
void (*fn)());
|
|
||||||
/*@=declundef@*/
|
|
||||||
/*@=exportheader@*/
|
|
||||||
|
|
||||||
void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
|
||||||
void (*fn)(),
|
|
||||||
/*@out@*/ void *rvalue,
|
|
||||||
/*@dependent@*/ void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
if ((rvalue == NULL) &&
|
|
||||||
(cif->rtype->type == FFI_TYPE_STRUCT))
|
|
||||||
{
|
|
||||||
/*@-sysunrecog@*/
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
/*@=sysunrecog@*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_SYSV:
|
|
||||||
/*@-usedef@*/
|
|
||||||
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
/*@=usedef@*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
sysv.S - Copyright (c) 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
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
|
|
||||||
``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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
#ifdef HAVE_MACHINE_ASM_H
|
|
||||||
#include <machine/asm.h>
|
|
||||||
#else
|
|
||||||
/* XXX these lose for some platforms, I'm sure. */
|
|
||||||
#define CNAME(x) x
|
|
||||||
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
# a1: ffi_prep_args
|
|
||||||
# a2: &ecif
|
|
||||||
# a3: cif->bytes
|
|
||||||
# a4: fig->flags
|
|
||||||
# sp+0: ecif.rvalue
|
|
||||||
# sp+4: fn
|
|
||||||
|
|
||||||
# This assumes we are using gas.
|
|
||||||
ENTRY(ffi_call_SYSV)
|
|
||||||
# Save registers
|
|
||||||
stmfd sp!, {a1-a4, fp, lr}
|
|
||||||
mov fp, sp
|
|
||||||
|
|
||||||
# Make room for all of the new args.
|
|
||||||
sub sp, fp, a3
|
|
||||||
|
|
||||||
# Place all of the ffi_prep_args in position
|
|
||||||
mov ip, a1
|
|
||||||
mov a1, sp
|
|
||||||
# a2 already set
|
|
||||||
|
|
||||||
# And call
|
|
||||||
mov lr, pc
|
|
||||||
mov pc, ip
|
|
||||||
|
|
||||||
# move first 4 parameters in registers
|
|
||||||
ldr a1, [sp, #0]
|
|
||||||
ldr a2, [sp, #4]
|
|
||||||
ldr a3, [sp, #8]
|
|
||||||
ldr a4, [sp, #12]
|
|
||||||
|
|
||||||
# and adjust stack
|
|
||||||
ldr ip, [fp, #8]
|
|
||||||
cmp ip, #16
|
|
||||||
movge ip, #16
|
|
||||||
add sp, sp, ip
|
|
||||||
|
|
||||||
# call function
|
|
||||||
mov lr, pc
|
|
||||||
ldr pc, [fp, #28]
|
|
||||||
|
|
||||||
# Remove the space we pushed for the args
|
|
||||||
mov sp, fp
|
|
||||||
|
|
||||||
# Load a3 with the pointer to storage for the return value
|
|
||||||
ldr a3, [sp, #24]
|
|
||||||
|
|
||||||
# Load a4 with the return type code
|
|
||||||
ldr a4, [sp, #12]
|
|
||||||
|
|
||||||
# If the return value pointer is NULL, assume no return value.
|
|
||||||
cmp a3, #0
|
|
||||||
beq epilogue
|
|
||||||
|
|
||||||
# return INT
|
|
||||||
cmp a4, #FFI_TYPE_INT
|
|
||||||
streq a1, [a3]
|
|
||||||
beq epilogue
|
|
||||||
|
|
||||||
# return FLOAT
|
|
||||||
cmp a4, #FFI_TYPE_FLOAT
|
|
||||||
stfeqs f0, [a3]
|
|
||||||
beq epilogue
|
|
||||||
|
|
||||||
# return DOUBLE or LONGDOUBLE
|
|
||||||
cmp a4, #FFI_TYPE_DOUBLE
|
|
||||||
stfeqd f0, [a3]
|
|
||||||
|
|
||||||
epilogue:
|
|
||||||
ldmfd sp!, {a1-a4, fp, pc}
|
|
||||||
|
|
||||||
.ffi_call_SYSV_end:
|
|
||||||
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
|
||||||
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
debug.c - Copyright (c) 1996 Red Hat, 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 RED HAT 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 <stdio.h>
|
|
||||||
|
|
||||||
/* General debugging routines */
|
|
||||||
|
|
||||||
void ffi_stop_here(void)
|
|
||||||
{
|
|
||||||
/* This function is only useful for debugging purposes.
|
|
||||||
Place a breakpoint on ffi_stop_here to be notified of
|
|
||||||
significant events. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function should only be called via the FFI_ASSERT() macro */
|
|
||||||
|
|
||||||
int ffi_assert(char *file, int line)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "ASSERTION FAILURE: %s line %d\n", file, line);
|
|
||||||
ffi_stop_here();
|
|
||||||
abort();
|
|
||||||
|
|
||||||
/* This has to return something for the compiler not to complain */
|
|
||||||
/*@notreached@*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform a sanity check on an ffi_type structure */
|
|
||||||
|
|
||||||
bool ffi_type_test(ffi_type *a)
|
|
||||||
{
|
|
||||||
/*@-usedef@*/
|
|
||||||
FFI_ASSERT(a->type <= FFI_TYPE_LAST);
|
|
||||||
FFI_ASSERT(a->type > FFI_TYPE_VOID ? a->size > 0 : 1);
|
|
||||||
FFI_ASSERT(a->type > FFI_TYPE_VOID ? a->alignment > 0 : 1);
|
|
||||||
FFI_ASSERT(a->type == FFI_TYPE_STRUCT ? a->elements != NULL : 1);
|
|
||||||
/*@=usedef@*/
|
|
||||||
|
|
||||||
/* This is a silly thing to return, but it keeps the compiler from
|
|
||||||
issuing warnings about "a" not being used in non-debug builds. */
|
|
||||||
return (a != NULL);
|
|
||||||
}
|
|
||||||
@@ -1,736 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffitest.c - Copyright (c) 1996, 1997, 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
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 RED HAT 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <float.h>
|
|
||||||
|
|
||||||
/* This is lame. Long double support is barely there under SunOS 4.x */
|
|
||||||
#if defined(SPARC) && (SIZEOF_LONG_DOUBLE != 16)
|
|
||||||
#define BROKEN_LONG_DOUBLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CHECK(x) !(x) ? fail(__FILE__, __LINE__) : 0
|
|
||||||
|
|
||||||
static int fail(char *file, int line)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Test failure: %s line %d\n", file, line);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
/*@notreached@*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_ARGS 256
|
|
||||||
|
|
||||||
static size_t my_strlen(char *s)
|
|
||||||
{
|
|
||||||
return (strlen(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int promotion(signed char sc, signed short ss,
|
|
||||||
unsigned char uc, unsigned short us)
|
|
||||||
{
|
|
||||||
int r = (int) sc + (int) ss + (int) uc + (int) us;
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed char return_sc(signed char sc)
|
|
||||||
{
|
|
||||||
return sc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char return_uc(unsigned char uc)
|
|
||||||
{
|
|
||||||
return uc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long long return_ll(long long ll)
|
|
||||||
{
|
|
||||||
return ll;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int floating(int a, float b, double c, long double d, int e)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* This is ifdef'd out for now. long double support under SunOS/gcc
|
|
||||||
is pretty much non-existent. You'll get the odd bus error in library
|
|
||||||
routines like printf(). */
|
|
||||||
printf("%d %f %f %Lf %d\n", a, (double)b, c, d, e);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
i = (int) ((float)a/b + ((float)c/(float)d));
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float many(float f1,
|
|
||||||
float f2,
|
|
||||||
float f3,
|
|
||||||
float f4,
|
|
||||||
float f5,
|
|
||||||
float f6,
|
|
||||||
float f7,
|
|
||||||
float f8,
|
|
||||||
float f9,
|
|
||||||
float f10,
|
|
||||||
float f11,
|
|
||||||
float f12,
|
|
||||||
float f13)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
|
|
||||||
(double) f1, (double) f2, (double) f3, (double) f4, (double) f5,
|
|
||||||
(double) f6, (double) f7, (double) f8, (double) f9, (double) f10,
|
|
||||||
(double) f11, (double) f12, (double) f13);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13);
|
|
||||||
}
|
|
||||||
|
|
||||||
static double dblit(float f)
|
|
||||||
{
|
|
||||||
return f/3.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long double ldblit(float f)
|
|
||||||
{
|
|
||||||
return (long double) (((long double) f)/ (long double) 3.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned char uc;
|
|
||||||
double d;
|
|
||||||
unsigned int ui;
|
|
||||||
} test_structure_1;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
double d1;
|
|
||||||
double d2;
|
|
||||||
} test_structure_2;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int si;
|
|
||||||
} test_structure_3;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned ui1;
|
|
||||||
unsigned ui2;
|
|
||||||
unsigned ui3;
|
|
||||||
} test_structure_4;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char c1;
|
|
||||||
char c2;
|
|
||||||
} test_structure_5;
|
|
||||||
|
|
||||||
static test_structure_1 struct1(test_structure_1 ts)
|
|
||||||
{
|
|
||||||
/*@-type@*/
|
|
||||||
ts.uc++;
|
|
||||||
/*@=type@*/
|
|
||||||
ts.d--;
|
|
||||||
ts.ui++;
|
|
||||||
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static test_structure_2 struct2(test_structure_2 ts)
|
|
||||||
{
|
|
||||||
ts.d1--;
|
|
||||||
ts.d2--;
|
|
||||||
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static test_structure_3 struct3(test_structure_3 ts)
|
|
||||||
{
|
|
||||||
ts.si = -(ts.si*2);
|
|
||||||
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static test_structure_4 struct4(test_structure_4 ts)
|
|
||||||
{
|
|
||||||
ts.ui3 = ts.ui1 * ts.ui2 * ts.ui3;
|
|
||||||
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2)
|
|
||||||
{
|
|
||||||
ts1.c1 += ts2.c1;
|
|
||||||
ts1.c2 -= ts2.c2;
|
|
||||||
|
|
||||||
return ts1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Take an int and a float argument, together with int userdata, and */
|
|
||||||
/* return the sum. */
|
|
||||||
static void closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
|
|
||||||
{
|
|
||||||
*(int*)resp =
|
|
||||||
*(int *)args[0] + (int)(*(float *)args[1]) + (int)(long)userdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef int (*closure_test_type)(int, float);
|
|
||||||
|
|
||||||
int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
|
|
||||||
{
|
|
||||||
ffi_cif cif;
|
|
||||||
ffi_type *args[MAX_ARGS];
|
|
||||||
void *values[MAX_ARGS];
|
|
||||||
char *s;
|
|
||||||
signed char sc;
|
|
||||||
unsigned char uc;
|
|
||||||
signed short ss;
|
|
||||||
unsigned short us;
|
|
||||||
unsigned long ul;
|
|
||||||
long long ll;
|
|
||||||
float f;
|
|
||||||
double d;
|
|
||||||
long double ld;
|
|
||||||
signed int si1;
|
|
||||||
signed int si2;
|
|
||||||
|
|
||||||
#if defined(ALPHA) || defined(IA64) || defined(SPARC64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
|
|
||||||
long long rint;
|
|
||||||
#else
|
|
||||||
int rint;
|
|
||||||
#endif
|
|
||||||
long long rlonglong;
|
|
||||||
|
|
||||||
ffi_type ts1_type;
|
|
||||||
ffi_type ts2_type;
|
|
||||||
ffi_type ts3_type;
|
|
||||||
ffi_type ts4_type;
|
|
||||||
ffi_type ts5_type;
|
|
||||||
ffi_type *ts1_type_elements[4];
|
|
||||||
ffi_type *ts2_type_elements[3];
|
|
||||||
ffi_type *ts3_type_elements[2];
|
|
||||||
ffi_type *ts4_type_elements[4];
|
|
||||||
ffi_type *ts5_type_elements[3];
|
|
||||||
|
|
||||||
ts1_type.size = 0;
|
|
||||||
ts1_type.alignment = 0;
|
|
||||||
ts1_type.type = FFI_TYPE_STRUCT;
|
|
||||||
|
|
||||||
ts2_type.size = 0;
|
|
||||||
ts2_type.alignment = 0;
|
|
||||||
ts2_type.type = FFI_TYPE_STRUCT;
|
|
||||||
|
|
||||||
ts3_type.size = 0;
|
|
||||||
ts3_type.alignment = 0;
|
|
||||||
ts3_type.type = FFI_TYPE_STRUCT;
|
|
||||||
|
|
||||||
ts4_type.size = 0;
|
|
||||||
ts4_type.alignment = 0;
|
|
||||||
ts4_type.type = FFI_TYPE_STRUCT;
|
|
||||||
|
|
||||||
ts5_type.size = 0;
|
|
||||||
ts5_type.alignment = 0;
|
|
||||||
ts5_type.type = FFI_TYPE_STRUCT;
|
|
||||||
|
|
||||||
/*@-immediatetrans@*/
|
|
||||||
ts1_type.elements = ts1_type_elements;
|
|
||||||
ts2_type.elements = ts2_type_elements;
|
|
||||||
ts3_type.elements = ts3_type_elements;
|
|
||||||
ts4_type.elements = ts4_type_elements;
|
|
||||||
ts5_type.elements = ts5_type_elements;
|
|
||||||
/*@=immediatetrans@*/
|
|
||||||
|
|
||||||
ts1_type_elements[0] = &ffi_type_uchar;
|
|
||||||
ts1_type_elements[1] = &ffi_type_double;
|
|
||||||
ts1_type_elements[2] = &ffi_type_uint;
|
|
||||||
ts1_type_elements[3] = NULL;
|
|
||||||
|
|
||||||
ts2_type_elements[0] = &ffi_type_double;
|
|
||||||
ts2_type_elements[1] = &ffi_type_double;
|
|
||||||
ts2_type_elements[2] = NULL;
|
|
||||||
|
|
||||||
ts3_type_elements[0] = &ffi_type_sint;
|
|
||||||
ts3_type_elements[1] = NULL;
|
|
||||||
|
|
||||||
ts4_type_elements[0] = &ffi_type_uint;
|
|
||||||
ts4_type_elements[1] = &ffi_type_uint;
|
|
||||||
ts4_type_elements[2] = &ffi_type_uint;
|
|
||||||
ts4_type_elements[3] = NULL;
|
|
||||||
|
|
||||||
ts5_type_elements[0] = &ffi_type_schar;
|
|
||||||
ts5_type_elements[1] = &ffi_type_schar;
|
|
||||||
ts5_type_elements[2] = NULL;
|
|
||||||
|
|
||||||
ul = 0;
|
|
||||||
|
|
||||||
/* return value tests */
|
|
||||||
{
|
|
||||||
#if defined(MIPS) /* || defined(ARM) */
|
|
||||||
puts ("long long tests not run. This is a known bug on this architecture.");
|
|
||||||
#else
|
|
||||||
args[0] = &ffi_type_sint64;
|
|
||||||
values[0] = ≪
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ffi_type_sint64, args) == FFI_OK);
|
|
||||||
|
|
||||||
for (ll = 0LL; ll < 100LL; ll++)
|
|
||||||
{
|
|
||||||
ul++;
|
|
||||||
ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
|
|
||||||
CHECK(rlonglong == ll);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ll = 55555555555000LL; ll < 55555555555100LL; ll++)
|
|
||||||
{
|
|
||||||
ul++;
|
|
||||||
ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
|
|
||||||
CHECK(rlonglong == ll);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
args[0] = &ffi_type_schar;
|
|
||||||
values[0] = ≻
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ffi_type_schar, args) == FFI_OK);
|
|
||||||
|
|
||||||
for (sc = (signed char) -127;
|
|
||||||
sc < (signed char) 127; /*@-type@*/ sc++ /*@=type@*/)
|
|
||||||
{
|
|
||||||
ul++;
|
|
||||||
ffi_call(&cif, FFI_FN(return_sc), &rint, values);
|
|
||||||
CHECK(rint == (int) sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
args[0] = &ffi_type_uchar;
|
|
||||||
values[0] = &uc;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ffi_type_uchar, args) == FFI_OK);
|
|
||||||
|
|
||||||
for (uc = (unsigned char) '\x00';
|
|
||||||
uc < (unsigned char) '\xff'; /*@-type@*/ uc++ /*@=type@*/)
|
|
||||||
{
|
|
||||||
ul++;
|
|
||||||
ffi_call(&cif, FFI_FN(return_uc), &rint, values);
|
|
||||||
CHECK(rint == (signed int) uc);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%lu return value tests run\n", ul);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BROKEN_LONG_DOUBLE
|
|
||||||
printf ("This architecture has broken `long double' support. No floating point\ntests have been run.\n");
|
|
||||||
#else
|
|
||||||
/* float arg tests */
|
|
||||||
{
|
|
||||||
args[0] = &ffi_type_float;
|
|
||||||
values[0] = &f;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ffi_type_longdouble, args) == FFI_OK);
|
|
||||||
|
|
||||||
f = 3.14159;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* This is ifdef'd out for now. long double support under SunOS/gcc
|
|
||||||
is pretty much non-existent. You'll get the odd bus error in library
|
|
||||||
routines like printf(). */
|
|
||||||
printf ("%Lf\n", ldblit(f));
|
|
||||||
#endif
|
|
||||||
ld = 666;
|
|
||||||
ffi_call(&cif, FFI_FN(ldblit), &ld, values);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* This is ifdef'd out for now. long double support under SunOS/gcc
|
|
||||||
is pretty much non-existent. You'll get the odd bus error in library
|
|
||||||
routines like printf(). */
|
|
||||||
printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* These are not always the same!! Check for a reasonable delta */
|
|
||||||
/*@-realcompare@*/
|
|
||||||
if (ld - ldblit(f) < LDBL_EPSILON)
|
|
||||||
/*@=realcompare@*/
|
|
||||||
puts("long double return value tests ok!");
|
|
||||||
else
|
|
||||||
CHECK(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* float arg tests */
|
|
||||||
{
|
|
||||||
args[0] = &ffi_type_sint;
|
|
||||||
values[0] = &si1;
|
|
||||||
args[1] = &ffi_type_float;
|
|
||||||
values[1] = &f;
|
|
||||||
args[2] = &ffi_type_double;
|
|
||||||
values[2] = &d;
|
|
||||||
args[3] = &ffi_type_longdouble;
|
|
||||||
values[3] = &ld;
|
|
||||||
args[4] = &ffi_type_sint;
|
|
||||||
values[4] = &si2;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 5,
|
|
||||||
&ffi_type_sint, args) == FFI_OK);
|
|
||||||
|
|
||||||
si1 = 6;
|
|
||||||
f = 3.14159;
|
|
||||||
d = (double)1.0/(double)3.0;
|
|
||||||
ld = 2.71828182846L;
|
|
||||||
si2 = 10;
|
|
||||||
|
|
||||||
floating (si1, f, d, ld, si2);
|
|
||||||
|
|
||||||
ffi_call(&cif, FFI_FN(floating), &rint, values);
|
|
||||||
|
|
||||||
printf ("%d vs %d\n", rint, floating (si1, f, d, ld, si2));
|
|
||||||
|
|
||||||
CHECK(rint == floating(si1, f, d, ld, si2));
|
|
||||||
|
|
||||||
printf("float arg tests ok!\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* strlen tests */
|
|
||||||
{
|
|
||||||
args[0] = &ffi_type_pointer;
|
|
||||||
values[0] = (void*) &s;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ffi_type_sint, args) == FFI_OK);
|
|
||||||
|
|
||||||
s = "a";
|
|
||||||
ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
|
|
||||||
CHECK(rint == 1);
|
|
||||||
|
|
||||||
s = "1234567";
|
|
||||||
ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
|
|
||||||
CHECK(rint == 7);
|
|
||||||
|
|
||||||
s = "1234567890123456789012345";
|
|
||||||
ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
|
|
||||||
CHECK(rint == 25);
|
|
||||||
|
|
||||||
printf("strlen tests passed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* float arg tests */
|
|
||||||
{
|
|
||||||
args[0] = &ffi_type_float;
|
|
||||||
values[0] = &f;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ffi_type_double, args) == FFI_OK);
|
|
||||||
|
|
||||||
f = 3.14159;
|
|
||||||
|
|
||||||
ffi_call(&cif, FFI_FN(dblit), &d, values);
|
|
||||||
|
|
||||||
/* These are not always the same!! Check for a reasonable delta */
|
|
||||||
/*@-realcompare@*/
|
|
||||||
CHECK(d - dblit(f) < DBL_EPSILON);
|
|
||||||
/*@=realcompare@*/
|
|
||||||
|
|
||||||
printf("double return value tests ok!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* many arg tests */
|
|
||||||
{
|
|
||||||
float ff;
|
|
||||||
float fa[13];
|
|
||||||
|
|
||||||
for (ul = 0; ul < 13; ul++)
|
|
||||||
{
|
|
||||||
args[ul] = &ffi_type_float;
|
|
||||||
values[ul] = &fa[ul];
|
|
||||||
fa[ul] = (float) ul;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13,
|
|
||||||
&ffi_type_float, args) == FFI_OK);
|
|
||||||
|
|
||||||
/*@-usedef@*/
|
|
||||||
ff = many(fa[0], fa[1],
|
|
||||||
fa[2], fa[3],
|
|
||||||
fa[4], fa[5],
|
|
||||||
fa[6], fa[7],
|
|
||||||
fa[8], fa[9],
|
|
||||||
fa[10],fa[11],fa[12]);
|
|
||||||
/*@=usedef@*/
|
|
||||||
|
|
||||||
ffi_call(&cif, FFI_FN(many), &f, values);
|
|
||||||
|
|
||||||
/*@-realcompare@*/
|
|
||||||
if (f - ff < FLT_EPSILON)
|
|
||||||
/*@=realcompare@*/
|
|
||||||
printf("many arg tests ok!\n");
|
|
||||||
else
|
|
||||||
#ifdef POWERPC
|
|
||||||
printf("many arg tests failed! This is a gcc bug.\n");
|
|
||||||
#else
|
|
||||||
CHECK(0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* promotion tests */
|
|
||||||
{
|
|
||||||
args[0] = &ffi_type_schar;
|
|
||||||
args[1] = &ffi_type_sshort;
|
|
||||||
args[2] = &ffi_type_uchar;
|
|
||||||
args[3] = &ffi_type_ushort;
|
|
||||||
values[0] = ≻
|
|
||||||
values[1] = &ss;
|
|
||||||
values[2] = &uc;
|
|
||||||
values[3] = &us;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
|
|
||||||
&ffi_type_sint, args) == FFI_OK);
|
|
||||||
|
|
||||||
us = 0;
|
|
||||||
ul = 0;
|
|
||||||
|
|
||||||
for (sc = (signed char) -127;
|
|
||||||
sc <= (signed char) 120; /*@-type@*/ sc += 1 /*@=type@*/)
|
|
||||||
for (ss = -30000; ss <= 30000; ss += 10000)
|
|
||||||
for (uc = (unsigned char) 0;
|
|
||||||
uc <= (unsigned char) 200; /*@-type@*/ uc += 20 /*@=type@*/)
|
|
||||||
for (us = 0; us <= 60000; us += 10000)
|
|
||||||
{
|
|
||||||
ul++;
|
|
||||||
ffi_call(&cif, FFI_FN(promotion), &rint, values);
|
|
||||||
CHECK(rint == (int) sc + (int) ss + (int) uc + (int) us);
|
|
||||||
}
|
|
||||||
printf("%lu promotion tests run\n", ul);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef X86_WIN32 /* Structures dont work on Win32 */
|
|
||||||
|
|
||||||
/* struct tests */
|
|
||||||
{
|
|
||||||
test_structure_1 ts1_arg;
|
|
||||||
/* This is a hack to get a properly aligned result buffer */
|
|
||||||
test_structure_1 *ts1_result =
|
|
||||||
(test_structure_1 *) malloc (sizeof(test_structure_1));
|
|
||||||
|
|
||||||
args[0] = &ts1_type;
|
|
||||||
values[0] = &ts1_arg;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ts1_type, args) == FFI_OK);
|
|
||||||
|
|
||||||
ts1_arg.uc = '\x01';
|
|
||||||
ts1_arg.d = 3.14159;
|
|
||||||
ts1_arg.ui = 555;
|
|
||||||
|
|
||||||
ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
|
|
||||||
|
|
||||||
CHECK(ts1_result->ui == 556);
|
|
||||||
CHECK(ts1_result->d == 3.14159 - 1);
|
|
||||||
|
|
||||||
puts ("structure test 1 ok!\n");
|
|
||||||
|
|
||||||
free (ts1_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* struct tests */
|
|
||||||
{
|
|
||||||
test_structure_2 ts2_arg;
|
|
||||||
|
|
||||||
/* This is a hack to get a properly aligned result buffer */
|
|
||||||
test_structure_2 *ts2_result =
|
|
||||||
(test_structure_2 *) malloc (sizeof(test_structure_2));
|
|
||||||
|
|
||||||
args[0] = &ts2_type;
|
|
||||||
values[0] = &ts2_arg;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ts2_type, args) == FFI_OK);
|
|
||||||
|
|
||||||
ts2_arg.d1 = 5.55;
|
|
||||||
ts2_arg.d2 = 6.66;
|
|
||||||
|
|
||||||
printf ("%g\n", ts2_result->d1);
|
|
||||||
printf ("%g\n", ts2_result->d2);
|
|
||||||
|
|
||||||
ffi_call(&cif, FFI_FN(struct2), ts2_result, values);
|
|
||||||
|
|
||||||
printf ("%g\n", ts2_result->d1);
|
|
||||||
printf ("%g\n", ts2_result->d2);
|
|
||||||
|
|
||||||
CHECK(ts2_result->d1 == 5.55 - 1);
|
|
||||||
CHECK(ts2_result->d2 == 6.66 - 1);
|
|
||||||
|
|
||||||
printf("structure test 2 ok!\n");
|
|
||||||
|
|
||||||
free (ts2_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* struct tests */
|
|
||||||
{
|
|
||||||
int compare_value;
|
|
||||||
test_structure_3 ts3_arg;
|
|
||||||
test_structure_3 *ts3_result =
|
|
||||||
(test_structure_3 *) malloc (sizeof(test_structure_3));
|
|
||||||
|
|
||||||
args[0] = &ts3_type;
|
|
||||||
values[0] = &ts3_arg;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ts3_type, args) == FFI_OK);
|
|
||||||
|
|
||||||
ts3_arg.si = -123;
|
|
||||||
compare_value = ts3_arg.si;
|
|
||||||
|
|
||||||
ffi_call(&cif, FFI_FN(struct3), ts3_result, values);
|
|
||||||
|
|
||||||
printf ("%d %d\n", ts3_result->si, -(compare_value*2));
|
|
||||||
|
|
||||||
if (ts3_result->si == -(ts3_arg.si*2))
|
|
||||||
puts ("structure test 3 ok!");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
puts ("Structure test 3 found structure passing bug.");
|
|
||||||
puts (" Current versions of GCC are not 100% compliant with the");
|
|
||||||
puts (" n32 ABI. There is a known problem related to passing");
|
|
||||||
puts (" small structures. Send a bug report to the gcc maintainers.");
|
|
||||||
}
|
|
||||||
|
|
||||||
free (ts3_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* struct tests */
|
|
||||||
{
|
|
||||||
test_structure_4 ts4_arg;
|
|
||||||
|
|
||||||
/* This is a hack to get a properly aligned result buffer */
|
|
||||||
test_structure_4 *ts4_result =
|
|
||||||
(test_structure_4 *) malloc (sizeof(test_structure_4));
|
|
||||||
|
|
||||||
args[0] = &ts4_type;
|
|
||||||
values[0] = &ts4_arg;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
|
||||||
&ts4_type, args) == FFI_OK);
|
|
||||||
|
|
||||||
ts4_arg.ui1 = 2;
|
|
||||||
ts4_arg.ui2 = 3;
|
|
||||||
ts4_arg.ui3 = 4;
|
|
||||||
|
|
||||||
ffi_call (&cif, FFI_FN(struct4), ts4_result, values);
|
|
||||||
|
|
||||||
if (ts4_result->ui3 == 2U * 3U * 4U)
|
|
||||||
puts ("structure test 4 ok!");
|
|
||||||
else
|
|
||||||
puts ("Structure test 4 found GCC's structure passing bug.");
|
|
||||||
|
|
||||||
free (ts4_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* struct tests */
|
|
||||||
{
|
|
||||||
test_structure_5 ts5_arg1, ts5_arg2;
|
|
||||||
|
|
||||||
/* This is a hack to get a properly aligned result buffer */
|
|
||||||
test_structure_5 *ts5_result =
|
|
||||||
(test_structure_5 *) malloc (sizeof(test_structure_5));
|
|
||||||
|
|
||||||
args[0] = &ts5_type;
|
|
||||||
args[1] = &ts5_type;
|
|
||||||
values[0] = &ts5_arg1;
|
|
||||||
values[1] = &ts5_arg2;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2,
|
|
||||||
&ts5_type, args) == FFI_OK);
|
|
||||||
|
|
||||||
ts5_arg1.c1 = 2;
|
|
||||||
ts5_arg1.c2 = 6;
|
|
||||||
ts5_arg2.c1 = 5;
|
|
||||||
ts5_arg2.c2 = 3;
|
|
||||||
|
|
||||||
ffi_call (&cif, FFI_FN(struct5), ts5_result, values);
|
|
||||||
|
|
||||||
if (ts5_result->c1 == 7
|
|
||||||
&& ts5_result->c2 == 3)
|
|
||||||
puts ("structure test 5 ok!");
|
|
||||||
else
|
|
||||||
puts ("Structure test 5 found GCC's structure passing bug.");
|
|
||||||
|
|
||||||
free (ts5_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
printf("Structure passing doesn't work on Win32.\n");
|
|
||||||
#endif /* X86_WIN32 */
|
|
||||||
|
|
||||||
# if FFI_CLOSURES
|
|
||||||
/* A simple closure test */
|
|
||||||
{
|
|
||||||
ffi_closure cl;
|
|
||||||
ffi_type * cl_arg_types[3];
|
|
||||||
|
|
||||||
cl_arg_types[0] = &ffi_type_sint;
|
|
||||||
cl_arg_types[1] = &ffi_type_float;
|
|
||||||
cl_arg_types[2] = NULL;
|
|
||||||
|
|
||||||
/* Initialize the cif */
|
|
||||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2,
|
|
||||||
&ffi_type_sint, cl_arg_types) == FFI_OK);
|
|
||||||
|
|
||||||
CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn,
|
|
||||||
(void *) 3 /* userdata */)
|
|
||||||
== FFI_OK);
|
|
||||||
CHECK((*((closure_test_type)(&cl)))(1, 2.0) == 6);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/* If we arrived here, all is good */
|
|
||||||
(void) puts("\nLooks good. No surprises.\n");
|
|
||||||
|
|
||||||
/*@-compdestroy@*/
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,670 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 1998 Cygnus Solutions
|
|
||||||
Copyright (c) 2000 Hewlett Packard Company
|
|
||||||
|
|
||||||
IA64 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 CYGNUS SOLUTIONS 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 "ia64_flags.h"
|
|
||||||
|
|
||||||
/* Memory image of fp register contents. Should eventually be an fp */
|
|
||||||
/* type long enough to hold an entire register. For now we use double. */
|
|
||||||
typedef double float80;
|
|
||||||
|
|
||||||
/* The stack layout at call to ffi_prep_regs. Other_args will remain */
|
|
||||||
/* on the stack for the actual call. Everything else we be transferred */
|
|
||||||
/* to registers and popped by the assembly code. */
|
|
||||||
|
|
||||||
struct ia64_args {
|
|
||||||
long scratch[2]; /* Two scratch words at top of stack. */
|
|
||||||
/* Allows sp to passed as arg pointer. */
|
|
||||||
void * r8_contents; /* Value to be passed in r8 */
|
|
||||||
long spare; /* Not used. */
|
|
||||||
float80 fp_regs[8]; /* Contents of 8 floating point argument */
|
|
||||||
/* registers. */
|
|
||||||
long out_regs[8]; /* Contents of the 8 out registers used */
|
|
||||||
/* for integer parameters. */
|
|
||||||
long other_args[0]; /* Arguments passed on stack, variable size */
|
|
||||||
/* Treated as continuation of out_regs. */
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t float_type_size(unsigned short tp)
|
|
||||||
{
|
|
||||||
switch(tp) {
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
return sizeof(float);
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
return sizeof(double);
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
return sizeof(long double);
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Is type a struct containing at most n floats, doubles, or extended
|
|
||||||
* doubles, all of the same fp type?
|
|
||||||
* If so, set *element_type to the fp type.
|
|
||||||
*/
|
|
||||||
static bool is_homogeneous_fp_aggregate(ffi_type * type, int n,
|
|
||||||
unsigned short * element_type)
|
|
||||||
{
|
|
||||||
ffi_type **ptr;
|
|
||||||
unsigned short element, struct_element;
|
|
||||||
|
|
||||||
int type_set = 0;
|
|
||||||
|
|
||||||
FFI_ASSERT(type != NULL);
|
|
||||||
|
|
||||||
FFI_ASSERT(type->elements != NULL);
|
|
||||||
|
|
||||||
ptr = &(type->elements[0]);
|
|
||||||
|
|
||||||
while ((*ptr) != NULL)
|
|
||||||
{
|
|
||||||
switch((*ptr) -> type) {
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
if (type_set && element != FFI_TYPE_FLOAT) return 0;
|
|
||||||
if (--n < 0) return FALSE;
|
|
||||||
type_set = 1;
|
|
||||||
element = FFI_TYPE_FLOAT;
|
|
||||||
break;
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
if (type_set && element != FFI_TYPE_DOUBLE) return 0;
|
|
||||||
if (--n < 0) return FALSE;
|
|
||||||
type_set = 1;
|
|
||||||
element = FFI_TYPE_DOUBLE;
|
|
||||||
break;
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
if (!is_homogeneous_fp_aggregate(type, n, &struct_element))
|
|
||||||
return FALSE;
|
|
||||||
if (type_set && struct_element != element) return FALSE;
|
|
||||||
n -= (type -> size)/float_type_size(element);
|
|
||||||
element = struct_element;
|
|
||||||
if (n < 0) return FALSE;
|
|
||||||
break;
|
|
||||||
/* case FFI_TYPE_LONGDOUBLE:
|
|
||||||
Not yet implemented. */
|
|
||||||
default:
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
*element_type = element;
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space
|
|
||||||
has been allocated for the function's arguments. Returns nonzero
|
|
||||||
if fp registers are used for arguments. */
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ffi_prep_args(struct ia64_args *stack, extended_cif *ecif, int bytes)
|
|
||||||
{
|
|
||||||
register long i, avn;
|
|
||||||
register void **p_argv;
|
|
||||||
register long *argp = stack -> out_regs;
|
|
||||||
register float80 *fp_argp = stack -> fp_regs;
|
|
||||||
register ffi_type **p_arg;
|
|
||||||
|
|
||||||
/* For big return structs, r8 needs to contain the target address. */
|
|
||||||
/* Since r8 is otherwise dead, we set it unconditionally. */
|
|
||||||
stack -> r8_contents = ecif -> rvalue;
|
|
||||||
i = 0;
|
|
||||||
avn = ecif->cif->nargs;
|
|
||||||
p_arg = ecif->cif->arg_types;
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
while (i < avn)
|
|
||||||
{
|
|
||||||
size_t z; /* z is in units of arg slots or words, not bytes. */
|
|
||||||
|
|
||||||
switch ((*p_arg)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
z = 1;
|
|
||||||
*(SINT64 *) argp = *(SINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
z = 1;
|
|
||||||
*(UINT64 *) argp = *(UINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
z = 1;
|
|
||||||
*(SINT64 *) argp = *(SINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
z = 1;
|
|
||||||
*(UINT64 *) argp = *(UINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
z = 1;
|
|
||||||
*(SINT64 *) argp = *(SINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
z = 1;
|
|
||||||
*(UINT64 *) argp = *(UINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
z = 1;
|
|
||||||
*(UINT64 *) argp = *(UINT64 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
z = 1;
|
|
||||||
if (fp_argp - stack->fp_regs < 8)
|
|
||||||
{
|
|
||||||
/* Note the conversion -- all the fp regs are loaded as
|
|
||||||
doubles. */
|
|
||||||
*fp_argp++ = *(float *)(* p_argv);
|
|
||||||
}
|
|
||||||
/* Also put it into the integer registers or memory: */
|
|
||||||
*(UINT64 *) argp = *(UINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
z = 1;
|
|
||||||
if (fp_argp - stack->fp_regs < 8)
|
|
||||||
*fp_argp++ = *(double *)(* p_argv);
|
|
||||||
/* Also put it into the integer registers or memory: */
|
|
||||||
*(double *) argp = *(double *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
{
|
|
||||||
size_t sz = (*p_arg)->size;
|
|
||||||
unsigned short element_type;
|
|
||||||
z = ((*p_arg)->size + SIZEOF_ARG - 1)/SIZEOF_ARG;
|
|
||||||
if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
|
|
||||||
int i;
|
|
||||||
int nelements = sz/float_type_size(element_type);
|
|
||||||
for (i = 0; i < nelements; ++i) {
|
|
||||||
switch (element_type) {
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
if (fp_argp - stack->fp_regs < 8)
|
|
||||||
*fp_argp++ = ((float *)(* p_argv))[i];
|
|
||||||
break;
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
if (fp_argp - stack->fp_regs < 8)
|
|
||||||
*fp_argp++ = ((double *)(* p_argv))[i];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Extended precision not yet implemented. */
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* And pass it in integer registers as a struct, with */
|
|
||||||
/* its actual field sizes packed into registers. */
|
|
||||||
memcpy(argp, *p_argv, (*p_arg)->size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
argp += z;
|
|
||||||
i++, p_arg++, p_argv++;
|
|
||||||
}
|
|
||||||
return (fp_argp != stack -> fp_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
|
||||||
{
|
|
||||||
long i, avn;
|
|
||||||
bool is_simple = TRUE;
|
|
||||||
long simple_flag = FFI_SIMPLE_V;
|
|
||||||
/* Adjust cif->bytes to include space for the 2 scratch words,
|
|
||||||
r8 register contents, spare word,
|
|
||||||
the 8 fp register contents, and all 8 integer register contents.
|
|
||||||
This will be removed before the call, though 2 scratch words must
|
|
||||||
remain. */
|
|
||||||
|
|
||||||
cif->bytes += 4*sizeof(long) + 8 *sizeof(float80);
|
|
||||||
if (cif->bytes < sizeof(struct ia64_args))
|
|
||||||
cif->bytes = sizeof(struct ia64_args);
|
|
||||||
|
|
||||||
/* The stack must be double word aligned, so round bytes up
|
|
||||||
appropriately. */
|
|
||||||
|
|
||||||
cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
|
|
||||||
|
|
||||||
avn = cif->nargs;
|
|
||||||
if (avn <= 2) {
|
|
||||||
for (i = 0; i < avn; ++i) {
|
|
||||||
switch(cif -> arg_types[i] -> type) {
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
simple_flag = FFI_ADD_INT_ARG(simple_flag);
|
|
||||||
break;
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
simple_flag = FFI_ADD_LONG_ARG(simple_flag);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
is_simple = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
is_simple = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
cif->flags = FFI_TYPE_VOID;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
{
|
|
||||||
size_t sz = cif -> rtype -> size;
|
|
||||||
unsigned short element_type;
|
|
||||||
|
|
||||||
is_simple = FALSE;
|
|
||||||
if (is_homogeneous_fp_aggregate(cif -> rtype, 8, &element_type)) {
|
|
||||||
int nelements = sz/float_type_size(element_type);
|
|
||||||
if (nelements <= 1) {
|
|
||||||
if (0 == nelements) {
|
|
||||||
cif -> flags = FFI_TYPE_VOID;
|
|
||||||
} else {
|
|
||||||
cif -> flags = element_type;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch(element_type) {
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
cif -> flags = FFI_IS_FLOAT_FP_AGGREGATE | nelements;
|
|
||||||
break;
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif -> flags = FFI_IS_DOUBLE_FP_AGGREGATE | nelements;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* long double NYI */
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (sz <= 32) {
|
|
||||||
if (sz <= 8) {
|
|
||||||
cif->flags = FFI_TYPE_INT;
|
|
||||||
} else if (sz <= 16) {
|
|
||||||
cif->flags = FFI_IS_SMALL_STRUCT2;
|
|
||||||
} else if (sz <= 24) {
|
|
||||||
cif->flags = FFI_IS_SMALL_STRUCT3;
|
|
||||||
} else {
|
|
||||||
cif->flags = FFI_IS_SMALL_STRUCT4;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cif->flags = FFI_TYPE_STRUCT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
is_simple = FALSE;
|
|
||||||
cif->flags = FFI_TYPE_FLOAT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
is_simple = FALSE;
|
|
||||||
cif->flags = FFI_TYPE_DOUBLE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
cif->flags = FFI_TYPE_INT;
|
|
||||||
/* This seems to depend on little endian mode, and the fact that */
|
|
||||||
/* the return pointer always points to at least 8 bytes. But */
|
|
||||||
/* that also seems to be true for other platforms. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_simple) cif -> flags |= simple_flag;
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int ffi_call_unix(bool (*)(struct ia64_args *, extended_cif *, int),
|
|
||||||
extended_cif *, unsigned,
|
|
||||||
unsigned, unsigned *, void (*)());
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
long simple = cif -> flags & FFI_SIMPLE;
|
|
||||||
|
|
||||||
/* Should this also check for Unix ABI? */
|
|
||||||
/* This is almost, but not quite, machine independent. Note that */
|
|
||||||
/* we can get away with not caring about length of the result because */
|
|
||||||
/* we assume we are little endian, and the result buffer is large */
|
|
||||||
/* enough. */
|
|
||||||
/* This needs work for HP/UX. */
|
|
||||||
if (simple) {
|
|
||||||
long (*lfn)() = (long (*)())fn;
|
|
||||||
long result;
|
|
||||||
switch(simple) {
|
|
||||||
case FFI_SIMPLE_V:
|
|
||||||
result = lfn();
|
|
||||||
break;
|
|
||||||
case FFI_SIMPLE_I:
|
|
||||||
result = lfn(*(int *)avalue[0]);
|
|
||||||
break;
|
|
||||||
case FFI_SIMPLE_L:
|
|
||||||
result = lfn(*(long *)avalue[0]);
|
|
||||||
break;
|
|
||||||
case FFI_SIMPLE_II:
|
|
||||||
result = lfn(*(int *)avalue[0], *(int *)avalue[1]);
|
|
||||||
break;
|
|
||||||
case FFI_SIMPLE_IL:
|
|
||||||
result = lfn(*(int *)avalue[0], *(long *)avalue[1]);
|
|
||||||
break;
|
|
||||||
case FFI_SIMPLE_LI:
|
|
||||||
result = lfn(*(long *)avalue[0], *(int *)avalue[1]);
|
|
||||||
break;
|
|
||||||
case FFI_SIMPLE_LL:
|
|
||||||
result = lfn(*(long *)avalue[0], *(long *)avalue[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((cif->flags & ~FFI_SIMPLE) != FFI_TYPE_VOID && 0 != rvalue) {
|
|
||||||
* (long *)rvalue = result;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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. */
|
|
||||||
|
|
||||||
if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT)
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_UNIX:
|
|
||||||
ffi_call_unix(ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, rvalue, fn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Closures represent a pair consisting of a function pointer, and
|
|
||||||
* some user data. A closure is invoked by reinterpreting the closure
|
|
||||||
* as a function pointer, and branching to it. Thus we can make an
|
|
||||||
* interpreted function callable as a C function: We turn the interpreter
|
|
||||||
* itself, together with a pointer specifying the interpreted procedure,
|
|
||||||
* into a closure.
|
|
||||||
* On X86, the first few words of the closure structure actually contain code,
|
|
||||||
* which will do the right thing. On most other architectures, this
|
|
||||||
* would raise some Icache/Dcache coherence issues (which can be solved, but
|
|
||||||
* often not cheaply).
|
|
||||||
* For IA64, function pointer are already pairs consisting of a code
|
|
||||||
* pointer, and a gp pointer. The latter is needed to access global variables.
|
|
||||||
* Here we set up such a pair as the first two words of the closure (in
|
|
||||||
* the "trampoline" area), but we replace the gp pointer with a pointer
|
|
||||||
* to the closure itself. We also add the real gp pointer to the
|
|
||||||
* closure. This allows the function entry code to both retrieve the
|
|
||||||
* user data, and to restire the correct gp pointer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
|
|
||||||
void **avalue, ffi_cif *cif);
|
|
||||||
|
|
||||||
/* This function is entered with the doctored gp (r1) value.
|
|
||||||
* This code is extremely gcc specific. There is some argument that
|
|
||||||
* it should really be written in assembly code, since it depends on
|
|
||||||
* gcc properties that might change over time.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ffi_closure_UNIX is an assembly routine, which copies the register */
|
|
||||||
/* state into s struct ia64_args, and the invokes */
|
|
||||||
/* ffi_closure_UNIX_inner. It also recovers the closure pointer */
|
|
||||||
/* from its fake gp pointer. */
|
|
||||||
void ffi_closure_UNIX();
|
|
||||||
|
|
||||||
#ifndef __GNUC__
|
|
||||||
# error This requires gcc
|
|
||||||
#endif
|
|
||||||
void
|
|
||||||
ffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)
|
|
||||||
/* Hopefully declarint this as a varargs function will force all args */
|
|
||||||
/* to memory. */
|
|
||||||
{
|
|
||||||
// this is our return value storage
|
|
||||||
long double res;
|
|
||||||
|
|
||||||
// our various things...
|
|
||||||
ffi_cif *cif;
|
|
||||||
unsigned short rtype;
|
|
||||||
void *resp;
|
|
||||||
void **arg_area;
|
|
||||||
|
|
||||||
resp = (void*)&res;
|
|
||||||
cif = closure->cif;
|
|
||||||
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
|
||||||
|
|
||||||
/* this call will initialize ARG_AREA, such that each
|
|
||||||
* element in that array points to the corresponding
|
|
||||||
* value on the stack; and if the function returns
|
|
||||||
* a structure, it will re-set RESP to point to the
|
|
||||||
* structure return address. */
|
|
||||||
|
|
||||||
ffi_prep_incoming_args_UNIX(args, (void**)&resp, arg_area, cif);
|
|
||||||
|
|
||||||
(closure->fun) (cif, resp, arg_area, closure->user_data);
|
|
||||||
|
|
||||||
rtype = cif->flags;
|
|
||||||
|
|
||||||
/* now, do a generic return based on the value of rtype */
|
|
||||||
if (rtype == FFI_TYPE_INT)
|
|
||||||
{
|
|
||||||
asm volatile ("ld8 r8=[%0]" : : "r" (resp) : "r8");
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_FLOAT)
|
|
||||||
{
|
|
||||||
asm volatile ("ldfs f8=[%0]" : : "r" (resp) : "f8");
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_DOUBLE)
|
|
||||||
{
|
|
||||||
asm volatile ("ldfd f8=[%0]" : : "r" (resp) : "f8");
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_IS_SMALL_STRUCT2)
|
|
||||||
{
|
|
||||||
asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
|
|
||||||
: : "r" (resp), "r" (resp+8) : "r8","r9");
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_IS_SMALL_STRUCT3)
|
|
||||||
{
|
|
||||||
asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
|
|
||||||
: : "r" (resp), "r" (resp+8), "r" (resp+16)
|
|
||||||
: "r8","r9","r10");
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_IS_SMALL_STRUCT4)
|
|
||||||
{
|
|
||||||
asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
|
|
||||||
: : "r" (resp), "r" (resp+8), "r" (resp+16), "r" (resp+24)
|
|
||||||
: "r8","r9","r10","r11");
|
|
||||||
}
|
|
||||||
else if (rtype != FFI_TYPE_VOID && rtype != FFI_TYPE_STRUCT)
|
|
||||||
{
|
|
||||||
/* Can only happen for homogeneous FP aggregates? */
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
|
|
||||||
void **avalue, ffi_cif *cif)
|
|
||||||
{
|
|
||||||
register unsigned int i;
|
|
||||||
register unsigned int avn;
|
|
||||||
register void **p_argv;
|
|
||||||
register unsigned long *argp = args -> out_regs;
|
|
||||||
unsigned fp_reg_num = 0;
|
|
||||||
register ffi_type **p_arg;
|
|
||||||
|
|
||||||
avn = cif->nargs;
|
|
||||||
p_argv = avalue;
|
|
||||||
|
|
||||||
for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)
|
|
||||||
{
|
|
||||||
size_t z; /* In units of words or argument slots. */
|
|
||||||
|
|
||||||
switch ((*p_arg)->type)
|
|
||||||
{
|
|
||||||
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:
|
|
||||||
z = 1;
|
|
||||||
*p_argv = (void *)argp;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
z = 1;
|
|
||||||
/* Convert argument back to float in place from the saved value */
|
|
||||||
if (fp_reg_num < 8) {
|
|
||||||
*(float *)argp = args -> fp_regs[fp_reg_num++];
|
|
||||||
} else {
|
|
||||||
*(float *)argp = *(double *)argp;
|
|
||||||
}
|
|
||||||
*p_argv = (void *)argp;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
z = 1;
|
|
||||||
if (fp_reg_num < 8) {
|
|
||||||
*p_argv = args -> fp_regs + fp_reg_num++;
|
|
||||||
} else {
|
|
||||||
*p_argv = (void *)argp;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
{
|
|
||||||
size_t sz = (*p_arg)->size;
|
|
||||||
unsigned short element_type;
|
|
||||||
z = ((*p_arg)->size + SIZEOF_ARG - 1)/SIZEOF_ARG;
|
|
||||||
if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
|
|
||||||
int nelements = sz/float_type_size(element_type);
|
|
||||||
if (nelements + fp_reg_num >= 8) {
|
|
||||||
/* hard case NYI. */
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
if (element_type == FFI_TYPE_DOUBLE) {
|
|
||||||
*p_argv = args -> fp_regs + fp_reg_num;
|
|
||||||
fp_reg_num += nelements;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (element_type == FFI_TYPE_FLOAT) {
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < nelements; ++ j) {
|
|
||||||
((float *)argp)[j] = args -> fp_regs[fp_reg_num + j];
|
|
||||||
}
|
|
||||||
*p_argv = (void *)argp;
|
|
||||||
fp_reg_num += nelements;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
abort(); /* Other fp types NYI */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
argp += z;
|
|
||||||
p_argv++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Fill in a closure to refer to the specified fun and user_data. */
|
|
||||||
/* cif specifies the argument and result types for fun. */
|
|
||||||
/* the cif must already be prep'ed */
|
|
||||||
|
|
||||||
/* The layout of a function descriptor. A C function pointer really */
|
|
||||||
/* points to one of these. */
|
|
||||||
typedef struct ia64_fd_struct {
|
|
||||||
void *code_pointer;
|
|
||||||
void *gp;
|
|
||||||
} ia64_fd;
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_closure (ffi_closure* closure,
|
|
||||||
ffi_cif* cif,
|
|
||||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct ffi_ia64_trampoline_struct *tramp =
|
|
||||||
(struct ffi_ia64_trampoline_struct *) (closure -> tramp);
|
|
||||||
ia64_fd *fd = (ia64_fd *)(void *)ffi_closure_UNIX;
|
|
||||||
|
|
||||||
FFI_ASSERT (cif->abi == FFI_UNIX);
|
|
||||||
|
|
||||||
tramp -> code_pointer = fd -> code_pointer;
|
|
||||||
tramp -> real_gp = fd -> gp;
|
|
||||||
tramp -> fake_gp = closure;
|
|
||||||
closure->cif = cif;
|
|
||||||
closure->user_data = user_data;
|
|
||||||
closure->fun = fun;
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company
|
|
||||||
|
|
||||||
IA64/unix Foreign Function Interface
|
|
||||||
|
|
||||||
Original author: Hans Boehm, HP Labs
|
|
||||||
|
|
||||||
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 CYGNUS SOLUTIONS 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.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
/* Homogeneous Floating Point Aggregates (HFAs) which are returned */
|
|
||||||
/* in FP registers. The least significant bits specify the size in */
|
|
||||||
/* words. */
|
|
||||||
#define FFI_IS_FLOAT_FP_AGGREGATE 0x1000
|
|
||||||
#define FFI_IS_DOUBLE_FP_AGGREGATE 0x0800
|
|
||||||
#define FLOAT_FP_AGGREGATE_BIT 12
|
|
||||||
#define DOUBLE_FP_AGGREGATE_BIT 11
|
|
||||||
|
|
||||||
/* Small structures containing N words. If N=1, they are returned */
|
|
||||||
/* as though they were integers. */
|
|
||||||
#define FFI_IS_SMALL_STRUCT2 0x40 /* Struct > 8, <=16 bytes */
|
|
||||||
#define FFI_IS_SMALL_STRUCT3 0x41 /* Struct > 16 <= 24 bytes */
|
|
||||||
#define FFI_IS_SMALL_STRUCT4 0x42 /* Struct > 24, <=32 bytes */
|
|
||||||
|
|
||||||
/* Flag values identifying particularly simple cases, which are */
|
|
||||||
/* handled specially. We treat functions as simple if they take all */
|
|
||||||
/* arguments can be passed as 32 or 64 bit integer quantities, there is */
|
|
||||||
/* either no return value or it can be treated as a 64bit integer, and */
|
|
||||||
/* if there are at most 2 arguments. */
|
|
||||||
/* This is OR'ed with the normal flag values. */
|
|
||||||
#define FFI_SIMPLE_V 0x10000 /* () -> X */
|
|
||||||
#define FFI_SIMPLE_I 0x20000 /* (int) -> X */
|
|
||||||
#define FFI_SIMPLE_L 0x30000 /* (long) -> X */
|
|
||||||
#define FFI_SIMPLE_II 0x40000 /* (int,int) -> X */
|
|
||||||
#define FFI_SIMPLE_IL 0x50000 /* (int,long) -> X */
|
|
||||||
#define FFI_SIMPLE_LI 0x60000 /* (long,int) -> X */
|
|
||||||
#define FFI_SIMPLE_LL 0x70000 /* (long,long) -> X */
|
|
||||||
|
|
||||||
/* Mask for all of the FFI_SIMPLE bits: */
|
|
||||||
#define FFI_SIMPLE 0xf0000
|
|
||||||
|
|
||||||
/* An easy way to build FFI_SIMPLE flags from FFI_SIMPLE_V: */
|
|
||||||
#define FFI_ADD_LONG_ARG(flag) (((flag) << 1) | 0x10000)
|
|
||||||
#define FFI_ADD_INT_ARG(flag) ((flag) << 1)
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
unix.S - Copyright (c) 1998 Cygnus Solutions
|
|
||||||
Copyright (c) 2000 Hewlett Packard Company
|
|
||||||
|
|
||||||
IA64/unix Foreign Function Interface
|
|
||||||
|
|
||||||
Primary author: Hans Boehm, HP Labs
|
|
||||||
|
|
||||||
Loosely modeled on Cygnus code for other platforms.
|
|
||||||
|
|
||||||
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
#include "ia64_flags.h"
|
|
||||||
|
|
||||||
/* parameters: */
|
|
||||||
#define callback in0
|
|
||||||
#define ecifp in1
|
|
||||||
#define bytes in2
|
|
||||||
#define flags in3
|
|
||||||
#define raddr in4
|
|
||||||
#define fn in5
|
|
||||||
|
|
||||||
#define FLOAT_SZ 8 /* in-memory size of fp operands */
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 16
|
|
||||||
.global ffi_call_unix#
|
|
||||||
.proc ffi_call_unix#
|
|
||||||
ffi_call_unix:
|
|
||||||
alloc loc0=ar.pfs,6,5,8,0
|
|
||||||
mov loc1=b0;
|
|
||||||
sub sp=sp,bytes
|
|
||||||
mov loc4=r1 /* Save gp */
|
|
||||||
ld8 r8=[callback],8 /* code address of callback */
|
|
||||||
;;
|
|
||||||
mov out0=sp
|
|
||||||
mov out1=ecifp
|
|
||||||
mov out2=bytes
|
|
||||||
ld8 r1=[callback] /* Set up gp for callback. Unnecessary? */
|
|
||||||
mov b6=r8
|
|
||||||
;;
|
|
||||||
br.call.sptk.many b0 = b6 /* call ffi_prep_args */
|
|
||||||
cmp.eq p6,p0=0,r8 /* r8 nonzero ==> need fp regs */
|
|
||||||
;;
|
|
||||||
(p6) add loc2=32+8*FLOAT_SZ,sp
|
|
||||||
(p6) br.cond.dptk.many fp_done
|
|
||||||
;; /* Quiets warning; needed? */
|
|
||||||
add loc2=32,sp
|
|
||||||
add loc3=32+FLOAT_SZ,sp
|
|
||||||
;;
|
|
||||||
ldfd f8=[loc2],2*FLOAT_SZ
|
|
||||||
ldfd f9=[loc3],2*FLOAT_SZ
|
|
||||||
;;
|
|
||||||
ldfd f10=[loc2],2*FLOAT_SZ
|
|
||||||
ldfd f11=[loc3],2*FLOAT_SZ
|
|
||||||
;;
|
|
||||||
ldfd f12=[loc2],2*FLOAT_SZ
|
|
||||||
ldfd f13=[loc3],2*FLOAT_SZ
|
|
||||||
;;
|
|
||||||
ldfd f14=[loc2],2*FLOAT_SZ
|
|
||||||
ldfd f15=[loc3]
|
|
||||||
fp_done:
|
|
||||||
add r9=16,sp /* Pointer to r8_contents */
|
|
||||||
/* loc2 points at first integer register value. */
|
|
||||||
add loc3=8,loc2
|
|
||||||
;;
|
|
||||||
ld8 r8=[r9] /* Just in case we return large struct */
|
|
||||||
ld8 out0=[loc2],16
|
|
||||||
ld8 out1=[loc3],16
|
|
||||||
;;
|
|
||||||
ld8 out2=[loc2],16
|
|
||||||
ld8 out3=[loc3],16
|
|
||||||
;;
|
|
||||||
ld8 out4=[loc2],16
|
|
||||||
ld8 out5=[loc3],16
|
|
||||||
;;
|
|
||||||
ld8 out6=[loc2],16
|
|
||||||
ld8 out7=[loc3]
|
|
||||||
/* loc2 points at first stack parameter. Set sp to 16 bytes */
|
|
||||||
/* below that. */
|
|
||||||
add sp=-16,loc2
|
|
||||||
|
|
||||||
ld8 r8=[fn],8
|
|
||||||
;;
|
|
||||||
ld8 r1=[fn] /* Set up gp */
|
|
||||||
mov b6=r8;;
|
|
||||||
br.call.sptk.many b0 = b6 /* call ffi_prep_args */
|
|
||||||
|
|
||||||
/* Handle return value. */
|
|
||||||
cmp.eq p6,p0=0,raddr
|
|
||||||
cmp.eq p7,p0=FFI_TYPE_INT,flags
|
|
||||||
cmp.eq p10,p0=FFI_IS_SMALL_STRUCT2,flags
|
|
||||||
cmp.eq p11,p0=FFI_IS_SMALL_STRUCT3,flags
|
|
||||||
cmp.eq p12,p0=FFI_IS_SMALL_STRUCT4,flags
|
|
||||||
;;
|
|
||||||
(p6) br.cond.dpnt.few done /* Dont copy ret values if raddr = 0 */
|
|
||||||
(p7) br.cond.dptk.few copy1
|
|
||||||
(p10) br.cond.dpnt.few copy2
|
|
||||||
(p11) br.cond.dpnt.few copy3
|
|
||||||
(p12) br.cond.dpnt.few copy4
|
|
||||||
cmp.eq p8,p0=FFI_TYPE_FLOAT,flags
|
|
||||||
cmp.eq p9,p0=FFI_TYPE_DOUBLE,flags
|
|
||||||
tbit.nz p6,p0=flags,FLOAT_FP_AGGREGATE_BIT
|
|
||||||
tbit.nz p7,p0=flags,DOUBLE_FP_AGGREGATE_BIT
|
|
||||||
;;
|
|
||||||
(p8) stfs [raddr]=f8
|
|
||||||
(p9) stfd [raddr]=f8
|
|
||||||
;;
|
|
||||||
(p6) br.cond.dpnt.few handle_float_hfa
|
|
||||||
(p7) br.cond.dpnt.few handle_double_hfa
|
|
||||||
br done
|
|
||||||
|
|
||||||
copy4:
|
|
||||||
add loc3=24,raddr
|
|
||||||
;;
|
|
||||||
st8 [loc3]=r11
|
|
||||||
copy3:
|
|
||||||
add loc3=16,raddr
|
|
||||||
;;
|
|
||||||
st8 [loc3]=r10
|
|
||||||
copy2:
|
|
||||||
add loc3=8,raddr
|
|
||||||
;;
|
|
||||||
st8 [loc3]=r9
|
|
||||||
copy1:
|
|
||||||
st8 [raddr]=r8
|
|
||||||
/* In the big struct case, raddr was passed as an argument. */
|
|
||||||
/* In the void case there was nothing to do. */
|
|
||||||
|
|
||||||
done:
|
|
||||||
mov r1=loc4 /* Restore gp */
|
|
||||||
mov ar.pfs = loc0
|
|
||||||
mov b0 = loc1
|
|
||||||
br.ret.sptk.many b0
|
|
||||||
|
|
||||||
handle_double_hfa:
|
|
||||||
/* Homogeneous floating point array of doubles is returned in */
|
|
||||||
/* registers f8-f15. Save one at a time to return area. */
|
|
||||||
and flags=0xf,flags /* Retrieve size */
|
|
||||||
;;
|
|
||||||
cmp.eq p6,p0=2,flags
|
|
||||||
cmp.eq p7,p0=3,flags
|
|
||||||
cmp.eq p8,p0=4,flags
|
|
||||||
cmp.eq p9,p0=5,flags
|
|
||||||
cmp.eq p10,p0=6,flags
|
|
||||||
cmp.eq p11,p0=7,flags
|
|
||||||
cmp.eq p12,p0=8,flags
|
|
||||||
;;
|
|
||||||
(p6) br.cond.dptk.few dhfa2
|
|
||||||
(p7) br.cond.dptk.few dhfa3
|
|
||||||
(p8) br.cond.dptk.few dhfa4
|
|
||||||
(p9) br.cond.dptk.few dhfa5
|
|
||||||
(p10) br.cond.dptk.few dhfa6
|
|
||||||
(p11) br.cond.dptk.few dhfa7
|
|
||||||
dhfa8: add loc3=7*8,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f15
|
|
||||||
dhfa7: add loc3=6*8,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f14
|
|
||||||
dhfa6: add loc3=5*8,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f13
|
|
||||||
dhfa5: add loc3=4*8,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f12
|
|
||||||
dhfa4: add loc3=3*8,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f11
|
|
||||||
dhfa3: add loc3=2*8,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f10
|
|
||||||
dhfa2: add loc3=1*8,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f9
|
|
||||||
stfd [raddr]=f8
|
|
||||||
br done
|
|
||||||
|
|
||||||
handle_float_hfa:
|
|
||||||
/* Homogeneous floating point array of floats is returned in */
|
|
||||||
/* registers f8-f15. Save one at a time to return area. */
|
|
||||||
and flags=0xf,flags /* Retrieve size */
|
|
||||||
;;
|
|
||||||
cmp.eq p6,p0=2,flags
|
|
||||||
cmp.eq p7,p0=3,flags
|
|
||||||
cmp.eq p8,p0=4,flags
|
|
||||||
cmp.eq p9,p0=5,flags
|
|
||||||
cmp.eq p10,p0=6,flags
|
|
||||||
cmp.eq p11,p0=7,flags
|
|
||||||
cmp.eq p12,p0=8,flags
|
|
||||||
;;
|
|
||||||
(p6) br.cond.dptk.few shfa2
|
|
||||||
(p7) br.cond.dptk.few shfa3
|
|
||||||
(p8) br.cond.dptk.few shfa4
|
|
||||||
(p9) br.cond.dptk.few shfa5
|
|
||||||
(p10) br.cond.dptk.few shfa6
|
|
||||||
(p11) br.cond.dptk.few shfa7
|
|
||||||
shfa8: add loc3=7*4,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f15
|
|
||||||
shfa7: add loc3=6*4,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f14
|
|
||||||
shfa6: add loc3=5*4,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f13
|
|
||||||
shfa5: add loc3=4*4,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f12
|
|
||||||
shfa4: add loc3=3*4,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f11
|
|
||||||
shfa3: add loc3=2*4,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f10
|
|
||||||
shfa2: add loc3=1*4,raddr
|
|
||||||
;;
|
|
||||||
stfd [loc3]=f9
|
|
||||||
stfd [raddr]=f8
|
|
||||||
br done
|
|
||||||
|
|
||||||
.endp ffi_call_unix
|
|
||||||
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 16
|
|
||||||
.global ffi_closure_UNIX
|
|
||||||
.proc ffi_closure_UNIX
|
|
||||||
ffi_closure_UNIX:
|
|
||||||
alloc loc0=ar.pfs,8,2,2,0
|
|
||||||
mov loc1=b0
|
|
||||||
/* Retrieve closure pointer and real gp. */
|
|
||||||
mov out0=gp
|
|
||||||
add gp=16,gp
|
|
||||||
;;
|
|
||||||
ld8 gp=[gp]
|
|
||||||
/* Reserve a structia64_args on the stack such that arguments */
|
|
||||||
/* past the first 8 are automatically placed in the right */
|
|
||||||
/* slot. Note that when we start the sp points at 2 8-byte */
|
|
||||||
/* scratch words, followed by the extra arguments. */
|
|
||||||
# define BASIC_ARGS_SZ (8*FLOAT_SZ+8*8+2*8)
|
|
||||||
# define FIRST_FP_OFFSET (4*8)
|
|
||||||
add r14=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET),sp
|
|
||||||
add r15=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET-FLOAT_SZ),sp
|
|
||||||
add sp=-BASIC_ARGS_SZ,sp
|
|
||||||
/* r14 points to fp_regs[0], r15 points to fp_regs[1] */
|
|
||||||
;;
|
|
||||||
stfd [r14]=f8,2*FLOAT_SZ
|
|
||||||
stfd [r15]=f9,2*FLOAT_SZ
|
|
||||||
;;
|
|
||||||
stfd [r14]=f10,2*FLOAT_SZ
|
|
||||||
stfd [r15]=f11,2*FLOAT_SZ
|
|
||||||
;;
|
|
||||||
stfd [r14]=f12,2*FLOAT_SZ
|
|
||||||
stfd [r15]=f13,2*FLOAT_SZ
|
|
||||||
;;
|
|
||||||
stfd [r14]=f14,FLOAT_SZ+8
|
|
||||||
stfd [r15]=f15,2*8
|
|
||||||
;;
|
|
||||||
/* r14 points to first parameter register area, r15 to second. */
|
|
||||||
st8 [r14]=in0,2*8
|
|
||||||
st8 [r15]=in1,2*8
|
|
||||||
;;
|
|
||||||
st8 [r14]=in2,2*8
|
|
||||||
st8 [r15]=in3,2*8
|
|
||||||
;;
|
|
||||||
st8 [r14]=in4,2*8
|
|
||||||
st8 [r15]=in5,2*8
|
|
||||||
;;
|
|
||||||
st8 [r14]=in6,2*8
|
|
||||||
st8 [r15]=in7,2*8
|
|
||||||
/* Call ffi_closure_UNIX_inner */
|
|
||||||
mov out1=sp
|
|
||||||
br.call.sptk.many b0=ffi_closure_UNIX_inner
|
|
||||||
;;
|
|
||||||
mov b0=loc1
|
|
||||||
mov ar.pfs=loc0
|
|
||||||
br.ret.sptk.many b0
|
|
||||||
.endp ffi_closure_UNIX
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
java_raw_api.c - Copyright (c) 1999 Cygnus Solutions
|
|
||||||
|
|
||||||
Cloned from raw_api.c
|
|
||||||
|
|
||||||
Raw_api.c author: Kresten Krab Thorup <krab@gnu.org>
|
|
||||||
Java_raw_api.c author: Hans-J. Boehm <hboehm@hpl.hp.com>
|
|
||||||
|
|
||||||
$Id $
|
|
||||||
|
|
||||||
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 RED HAT 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.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* This defines a Java- and 64-bit specific variant of the raw API. */
|
|
||||||
/* It assumes that "raw" argument blocks look like Java stacks on a */
|
|
||||||
/* 64-bit machine. Arguments that can be stored in a single stack */
|
|
||||||
/* stack slots (longs, doubles) occupy 128 bits, but only the first */
|
|
||||||
/* 64 bits are actually used. */
|
|
||||||
|
|
||||||
#include <ffi.h>
|
|
||||||
#include <ffi_common.h>
|
|
||||||
|
|
||||||
#if !defined(NO_JAVA_RAW_API) && !defined(FFI_NO_RAW_API)
|
|
||||||
|
|
||||||
size_t
|
|
||||||
ffi_java_raw_size (ffi_cif *cif)
|
|
||||||
{
|
|
||||||
size_t result = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ffi_type **at = cif->arg_types;
|
|
||||||
|
|
||||||
for (i = cif->nargs-1; i >= 0; i--, at++)
|
|
||||||
{
|
|
||||||
switch((*at) -> type) {
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
result += 2 * SIZEOF_ARG;
|
|
||||||
break;
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
/* No structure parameters in Java. */
|
|
||||||
abort();
|
|
||||||
default:
|
|
||||||
result += SIZEOF_ARG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
ffi_type **tp = cif->arg_types;
|
|
||||||
|
|
||||||
#if WORDS_BIGENDIAN
|
|
||||||
|
|
||||||
for (i = 0; i < cif->nargs; i++, tp++, args++)
|
|
||||||
{
|
|
||||||
switch ((*tp)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
*args = (void*) ((char*)(raw++) + SIZEOF_ARG - 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
*args = (void*) ((char*)(raw++) + SIZEOF_ARG - 2);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if SIZEOF_ARG >= 4
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
*args = (void*) ((char*)(raw++) + SIZEOF_ARG - 4);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SIZEOF_ARG == 8
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
*args = (void *)raw;
|
|
||||||
raw += 2;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
*args = (void*) &(raw++)->ptr;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
*args = raw;
|
|
||||||
raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* WORDS_BIGENDIAN */
|
|
||||||
|
|
||||||
#if !PDP
|
|
||||||
|
|
||||||
/* then assume little endian */
|
|
||||||
for (i = 0; i < cif->nargs; i++, tp++, args++)
|
|
||||||
{
|
|
||||||
#if SIZEOF_ARG == 8
|
|
||||||
switch((*tp)->type) {
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
*args = (void*) raw;
|
|
||||||
raw += 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*args = (void*) raw++;
|
|
||||||
}
|
|
||||||
#else /* SIZEOF_ARG != 8 */
|
|
||||||
*args = (void*) raw;
|
|
||||||
raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
|
|
||||||
#endif /* SIZEOF_ARG == 8 */
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "pdp endian not supported"
|
|
||||||
#endif /* ! PDP */
|
|
||||||
|
|
||||||
#endif /* WORDS_BIGENDIAN */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
ffi_type **tp = cif->arg_types;
|
|
||||||
|
|
||||||
for (i = 0; i < cif->nargs; i++, tp++, args++)
|
|
||||||
{
|
|
||||||
switch ((*tp)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
(raw++)->uint = *(UINT8*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
(raw++)->sint = *(SINT8*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
(raw++)->uint = *(UINT16*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
(raw++)->sint = *(SINT16*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if SIZEOF_ARG >= 4
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
(raw++)->uint = *(UINT32*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
(raw++)->sint = *(SINT32*) (*args);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
(raw++)->flt = *(FLOAT32*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if SIZEOF_ARG == 8
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
raw->uint = *(UINT64*) (*args);
|
|
||||||
raw += 2;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
(raw++)->ptr = **(void***) args;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
#if SIZEOF_ARG == 8
|
|
||||||
FFI_ASSERT(FALSE); /* Should have covered all cases */
|
|
||||||
#else
|
|
||||||
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
|
|
||||||
raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !FFI_NATIVE_RAW_API
|
|
||||||
|
|
||||||
|
|
||||||
/* This is a generic definition of ffi_raw_call, to be used if the
|
|
||||||
* native system does not provide a machine-specific implementation.
|
|
||||||
* Having this, allows code to be written for the raw API, without
|
|
||||||
* the need for system-specific code to handle input in that format;
|
|
||||||
* these following couple of functions will handle the translation forth
|
|
||||||
* and back automatically. */
|
|
||||||
|
|
||||||
void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif,
|
|
||||||
void (*fn)(),
|
|
||||||
/*@out@*/ void *rvalue,
|
|
||||||
/*@dependent@*/ ffi_raw *raw)
|
|
||||||
{
|
|
||||||
void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
|
|
||||||
ffi_java_raw_to_ptrarray (cif, raw, avalue);
|
|
||||||
ffi_call (cif, fn, rvalue, avalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FFI_CLOSURES /* base system provides closures */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_java_translate_args (ffi_cif *cif, void *rvalue,
|
|
||||||
void **avalue, void *user_data)
|
|
||||||
{
|
|
||||||
ffi_raw *raw = (ffi_raw*)alloca (ffi_java_raw_size (cif));
|
|
||||||
ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
|
|
||||||
|
|
||||||
ffi_java_ptrarray_to_raw (cif, avalue, raw);
|
|
||||||
(*cl->fun) (cif, rvalue, raw, cl->user_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Again, here is the generic version of ffi_prep_raw_closure, which
|
|
||||||
* will install an intermediate "hub" for translation of arguments from
|
|
||||||
* the pointer-array format, to the raw format */
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_java_raw_closure (ffi_raw_closure* cl,
|
|
||||||
ffi_cif *cif,
|
|
||||||
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
ffi_status status;
|
|
||||||
|
|
||||||
status = ffi_prep_closure ((ffi_closure*) cl,
|
|
||||||
cif,
|
|
||||||
&ffi_java_translate_args,
|
|
||||||
(void*)cl);
|
|
||||||
if (status == FFI_OK)
|
|
||||||
{
|
|
||||||
cl->fun = fun;
|
|
||||||
cl->user_data = user_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* FFI_CLOSURES */
|
|
||||||
#endif /* !FFI_NATIVE_RAW_API */
|
|
||||||
#endif /* !FFI_NO_RAW_API */
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c
|
|
||||||
|
|
||||||
m68k Foreign Function Interface
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#include <ffi.h>
|
|
||||||
#include <ffi_common.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space has
|
|
||||||
been allocated for the function's arguments. */
|
|
||||||
|
|
||||||
static void *
|
|
||||||
ffi_prep_args (void *stack, extended_cif *ecif)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
int tmp;
|
|
||||||
unsigned int avn;
|
|
||||||
void **p_argv;
|
|
||||||
char *argp;
|
|
||||||
ffi_type **p_arg;
|
|
||||||
void *struct_value_ptr;
|
|
||||||
|
|
||||||
tmp = 0;
|
|
||||||
argp = stack;
|
|
||||||
|
|
||||||
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
|
|
||||||
&& ecif->cif->rtype->size > 8)
|
|
||||||
struct_value_ptr = ecif->rvalue;
|
|
||||||
else
|
|
||||||
struct_value_ptr = NULL;
|
|
||||||
|
|
||||||
avn = ecif->cif->nargs;
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
|
|
||||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
|
||||||
i != 0 && avn != 0;
|
|
||||||
i--, p_arg++)
|
|
||||||
{
|
|
||||||
size_t z;
|
|
||||||
|
|
||||||
/* Align if necessary. */
|
|
||||||
if (((*p_arg)->alignment - 1) & (unsigned) argp)
|
|
||||||
argp = (char *) ALIGN (argp, (*p_arg)->alignment);
|
|
||||||
|
|
||||||
if (avn != 0)
|
|
||||||
{
|
|
||||||
avn--;
|
|
||||||
z = (*p_arg)->size;
|
|
||||||
if (z < sizeof (int))
|
|
||||||
{
|
|
||||||
switch ((*p_arg)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
*(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
*(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
*(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
*(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
memcpy (argp + sizeof (int) - z, *p_argv, z);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT (0);
|
|
||||||
}
|
|
||||||
z = sizeof (int);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memcpy (argp, *p_argv, z);
|
|
||||||
p_argv++;
|
|
||||||
argp += z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return struct_value_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CIF_FLAGS_INT 1
|
|
||||||
#define CIF_FLAGS_DINT 2
|
|
||||||
#define CIF_FLAGS_FLOAT 4
|
|
||||||
#define CIF_FLAGS_DOUBLE 8
|
|
||||||
#define CIF_FLAGS_LDOUBLE 16
|
|
||||||
#define CIF_FLAGS_POINTER 32
|
|
||||||
#define CIF_FLAGS_STRUCT 64
|
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_cif_machdep (ffi_cif *cif)
|
|
||||||
{
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
cif->flags = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
if (cif->rtype->size > 4 && cif->rtype->size <= 8)
|
|
||||||
cif->flags = CIF_FLAGS_DINT;
|
|
||||||
else if (cif->rtype->size <= 4)
|
|
||||||
cif->flags = CIF_FLAGS_STRUCT;
|
|
||||||
else
|
|
||||||
cif->flags = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
cif->flags = CIF_FLAGS_FLOAT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags = CIF_FLAGS_DOUBLE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
cif->flags = CIF_FLAGS_LDOUBLE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
cif->flags = CIF_FLAGS_POINTER;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
cif->flags = CIF_FLAGS_DINT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
cif->flags = CIF_FLAGS_INT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void ffi_call_SYSV (void *(*) (void *, extended_cif *),
|
|
||||||
extended_cif *,
|
|
||||||
unsigned, unsigned, unsigned,
|
|
||||||
void *, void (*fn) ());
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
|
|
||||||
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. */
|
|
||||||
|
|
||||||
if (rvalue == NULL
|
|
||||||
&& cif->rtype->type == FFI_TYPE_STRUCT
|
|
||||||
&& cif->rtype->size > 8)
|
|
||||||
ecif.rvalue = alloca (cif->rtype->size);
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_SYSV:
|
|
||||||
ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, cif->rtype->size * 8,
|
|
||||||
ecif.rvalue, fn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT (0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
sysv.S
|
|
||||||
|
|
||||||
m68k Foreign Function Interface
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
.globl ffi_call_SYSV
|
|
||||||
.type ffi_call_SYSV,@function
|
|
||||||
|
|
||||||
ffi_call_SYSV:
|
|
||||||
link %fp,#0
|
|
||||||
move.l %d2,-(%sp)
|
|
||||||
|
|
||||||
| Make room for all of the new args.
|
|
||||||
sub.l 16(%fp),%sp
|
|
||||||
|
|
||||||
| Call ffi_prep_args
|
|
||||||
move.l 12(%fp),-(%sp)
|
|
||||||
pea 4(%sp)
|
|
||||||
move.l 8(%fp),%a0
|
|
||||||
jsr (%a0)
|
|
||||||
addq.l #8,%sp
|
|
||||||
|
|
||||||
| Pass pointer to struct value, if any
|
|
||||||
move.l %a0,%a1
|
|
||||||
|
|
||||||
| Call the function
|
|
||||||
move.l 32(%fp),%a0
|
|
||||||
jsr (%a0)
|
|
||||||
|
|
||||||
| Remove the space we pushed for the args
|
|
||||||
add.l 16(%fp),%sp
|
|
||||||
|
|
||||||
| Load the pointer to storage for the return value
|
|
||||||
move.l 28(%fp),%a1
|
|
||||||
|
|
||||||
| Load the return type code
|
|
||||||
move.l 20(%fp),%d2
|
|
||||||
|
|
||||||
| If the return value pointer is NULL, assume no return value.
|
|
||||||
tst.l %a1
|
|
||||||
jbeq noretval
|
|
||||||
|
|
||||||
btst #0,%d2
|
|
||||||
jbeq retlongint
|
|
||||||
move.l %d0,(%a1)
|
|
||||||
jbra epilogue
|
|
||||||
|
|
||||||
retlongint:
|
|
||||||
btst #1,%d2
|
|
||||||
jbeq retfloat
|
|
||||||
move.l %d0,(%a1)
|
|
||||||
move.l %d1,4(%a1)
|
|
||||||
jbra epilogue
|
|
||||||
|
|
||||||
retfloat:
|
|
||||||
btst #2,%d2
|
|
||||||
jbeq retdouble
|
|
||||||
fmove.s %fp0,(%a1)
|
|
||||||
jbra epilogue
|
|
||||||
|
|
||||||
retdouble:
|
|
||||||
btst #3,%d2
|
|
||||||
jbeq retlongdouble
|
|
||||||
fmove.d %fp0,(%a1)
|
|
||||||
jbra epilogue
|
|
||||||
|
|
||||||
retlongdouble:
|
|
||||||
btst #4,%d2
|
|
||||||
jbeq retpointer
|
|
||||||
fmove.x %fp0,(%a1)
|
|
||||||
jbra epilogue
|
|
||||||
|
|
||||||
retpointer:
|
|
||||||
btst #5,%d2
|
|
||||||
jbeq retstruct
|
|
||||||
move.l %a0,(%a1)
|
|
||||||
jbra epilogue
|
|
||||||
|
|
||||||
retstruct:
|
|
||||||
btst #6,%d2
|
|
||||||
jbeq noretval
|
|
||||||
move.l 24(%fp),%d2
|
|
||||||
bfins %d0,(%a1){#0,%d2}
|
|
||||||
|
|
||||||
noretval:
|
|
||||||
epilogue:
|
|
||||||
move.l (%sp)+,%d2
|
|
||||||
unlk %a6
|
|
||||||
rts
|
|
||||||
.size ffi_call_SYSV,.-ffi_call_SYSV
|
|
||||||
@@ -1,469 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 1996 Cygnus Solutions
|
|
||||||
|
|
||||||
MIPS 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 CYGNUS SOLUTIONS 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>
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32
|
|
||||||
#define FIX_ARGP \
|
|
||||||
FFI_ASSERT(argp <= &stack[bytes]); \
|
|
||||||
if (argp == &stack[bytes]) \
|
|
||||||
{ \
|
|
||||||
argp = stack; \
|
|
||||||
ffi_stop_here(); \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define FIX_ARGP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space
|
|
||||||
has been allocated for the function's arguments */
|
|
||||||
|
|
||||||
static void ffi_prep_args(char *stack,
|
|
||||||
extended_cif *ecif,
|
|
||||||
int bytes,
|
|
||||||
int flags)
|
|
||||||
{
|
|
||||||
register int i;
|
|
||||||
register int avn;
|
|
||||||
register void **p_argv;
|
|
||||||
register char *argp;
|
|
||||||
register ffi_type **p_arg;
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32
|
|
||||||
/* If more than 8 double words are used, the remainder go
|
|
||||||
on the stack. We reorder stuff on the stack here to
|
|
||||||
support this easily. */
|
|
||||||
if (bytes > 8 * SIZEOF_ARG)
|
|
||||||
argp = &stack[bytes - (8 * SIZEOF_ARG)];
|
|
||||||
else
|
|
||||||
argp = stack;
|
|
||||||
#else
|
|
||||||
argp = stack;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memset(stack, 0, bytes);
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32
|
|
||||||
if ( ecif->cif->rstruct_flag != 0 )
|
|
||||||
#else
|
|
||||||
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
*(SLOT_TYPE_UNSIGNED *) argp = (SLOT_TYPE_UNSIGNED) ecif->rvalue;
|
|
||||||
argp += sizeof(SLOT_TYPE_UNSIGNED);
|
|
||||||
FIX_ARGP;
|
|
||||||
}
|
|
||||||
|
|
||||||
avn = ecif->cif->nargs;
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
|
|
||||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
|
||||||
i && avn;
|
|
||||||
i--, p_arg++)
|
|
||||||
{
|
|
||||||
size_t z;
|
|
||||||
|
|
||||||
/* Align if necessary */
|
|
||||||
if (((*p_arg)->alignment - 1) & (unsigned) argp) {
|
|
||||||
argp = (char *) ALIGN(argp, (*p_arg)->alignment);
|
|
||||||
FIX_ARGP;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
|
||||||
#define OFFSET 0
|
|
||||||
#else
|
|
||||||
#define OFFSET sizeof(int)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (avn)
|
|
||||||
{
|
|
||||||
avn--;
|
|
||||||
z = (*p_arg)->size;
|
|
||||||
if (z < sizeof(SLOT_TYPE_UNSIGNED))
|
|
||||||
{
|
|
||||||
z = sizeof(SLOT_TYPE_UNSIGNED);
|
|
||||||
|
|
||||||
switch ((*p_arg)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
*(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
*(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
*(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
*(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
*(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
*(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* This can only happen with 64bit slots */
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
*(float *) argp = *(float *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Handle small structures */
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
memcpy(argp, *p_argv, (*p_arg)->size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
|
||||||
memcpy(argp, *p_argv, z);
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
unsigned end = (unsigned) argp+z;
|
|
||||||
unsigned cap = (unsigned) stack+bytes;
|
|
||||||
|
|
||||||
/* Check if the data will fit within the register
|
|
||||||
space. Handle it if it doesn't. */
|
|
||||||
|
|
||||||
if (end <= cap)
|
|
||||||
memcpy(argp, *p_argv, z);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned portion = end - cap;
|
|
||||||
|
|
||||||
memcpy(argp, *p_argv, portion);
|
|
||||||
argp = stack;
|
|
||||||
memcpy(argp,
|
|
||||||
(void*)((unsigned)(*p_argv)+portion), z - portion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
p_argv++;
|
|
||||||
argp += z;
|
|
||||||
FIX_ARGP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32
|
|
||||||
|
|
||||||
/* The n32 spec says that if "a chunk consists solely of a double
|
|
||||||
float field (but not a double, which is part of a union), it
|
|
||||||
is passed in a floating point register. Any other chunk is
|
|
||||||
passed in an integer register". This code traverses structure
|
|
||||||
definitions and generates the appropriate flags. */
|
|
||||||
|
|
||||||
unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
|
|
||||||
{
|
|
||||||
unsigned flags = 0;
|
|
||||||
unsigned index = 0;
|
|
||||||
|
|
||||||
ffi_type *e;
|
|
||||||
|
|
||||||
while (e = arg->elements[index])
|
|
||||||
{
|
|
||||||
if (e->type == FFI_TYPE_DOUBLE)
|
|
||||||
{
|
|
||||||
flags += (FFI_TYPE_DOUBLE << *shift);
|
|
||||||
*shift += FFI_FLAG_BITS;
|
|
||||||
}
|
|
||||||
else if (e->type == FFI_TYPE_STRUCT)
|
|
||||||
flags += calc_n32_struct_flags(e, shift);
|
|
||||||
else
|
|
||||||
*shift += FFI_FLAG_BITS;
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned calc_n32_return_struct_flags(ffi_type *arg)
|
|
||||||
{
|
|
||||||
unsigned flags = 0;
|
|
||||||
unsigned index = 0;
|
|
||||||
unsigned small = FFI_TYPE_SMALLSTRUCT;
|
|
||||||
ffi_type *e;
|
|
||||||
|
|
||||||
/* Returning structures under n32 is a tricky thing.
|
|
||||||
A struct with only one or two floating point fields
|
|
||||||
is returned in $f0 (and $f2 if necessary). Any other
|
|
||||||
struct results at most 128 bits are returned in $2
|
|
||||||
(the first 64 bits) and $3 (remainder, if necessary).
|
|
||||||
Larger structs are handled normally. */
|
|
||||||
|
|
||||||
if (arg->size > 16)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (arg->size > 8)
|
|
||||||
small = FFI_TYPE_SMALLSTRUCT2;
|
|
||||||
|
|
||||||
e = arg->elements[0];
|
|
||||||
if (e->type == FFI_TYPE_DOUBLE)
|
|
||||||
flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
|
|
||||||
else if (e->type == FFI_TYPE_FLOAT)
|
|
||||||
flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
|
|
||||||
|
|
||||||
if (flags && (e = arg->elements[1]))
|
|
||||||
{
|
|
||||||
if (e->type == FFI_TYPE_DOUBLE)
|
|
||||||
flags += FFI_TYPE_DOUBLE;
|
|
||||||
else if (e->type == FFI_TYPE_FLOAT)
|
|
||||||
flags += FFI_TYPE_FLOAT;
|
|
||||||
else
|
|
||||||
return small;
|
|
||||||
|
|
||||||
if (flags && (arg->elements[2]))
|
|
||||||
{
|
|
||||||
/* There are three arguments and the first two are
|
|
||||||
floats! This must be passed the old way. */
|
|
||||||
return small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!flags)
|
|
||||||
return small;
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|
||||||
{
|
|
||||||
cif->flags = 0;
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
|
||||||
/* Set the flags necessary for O32 processing */
|
|
||||||
|
|
||||||
if (cif->rtype->type != FFI_TYPE_STRUCT)
|
|
||||||
{
|
|
||||||
if (cif->nargs > 0)
|
|
||||||
{
|
|
||||||
switch ((cif->arg_types)[0]->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags += (cif->arg_types)[0]->type;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cif->nargs > 1)
|
|
||||||
{
|
|
||||||
/* Only handle the second argument if the first
|
|
||||||
is a float or double. */
|
|
||||||
if (cif->flags)
|
|
||||||
{
|
|
||||||
switch ((cif->arg_types)[1]->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32
|
|
||||||
/* Set the flags necessary for N32 processing */
|
|
||||||
{
|
|
||||||
unsigned shift = 0;
|
|
||||||
unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
|
|
||||||
unsigned index = 0;
|
|
||||||
|
|
||||||
unsigned struct_flags = 0;
|
|
||||||
|
|
||||||
if (cif->rtype->type == FFI_TYPE_STRUCT)
|
|
||||||
{
|
|
||||||
struct_flags = calc_n32_return_struct_flags(cif->rtype);
|
|
||||||
|
|
||||||
if (struct_flags == 0)
|
|
||||||
{
|
|
||||||
/* This means that the structure is being passed as
|
|
||||||
a hidden argument */
|
|
||||||
|
|
||||||
shift = FFI_FLAG_BITS;
|
|
||||||
count = (cif->nargs < 7) ? cif->nargs : 7;
|
|
||||||
|
|
||||||
cif->rstruct_flag = !0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cif->rstruct_flag = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cif->rstruct_flag = 0;
|
|
||||||
|
|
||||||
while (count-- > 0)
|
|
||||||
{
|
|
||||||
switch ((cif->arg_types)[index]->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags += ((cif->arg_types)[index]->type << shift);
|
|
||||||
shift += FFI_FLAG_BITS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
|
|
||||||
&shift);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
shift += FFI_FLAG_BITS;
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
{
|
|
||||||
if (struct_flags == 0)
|
|
||||||
{
|
|
||||||
/* The structure is returned through a hidden
|
|
||||||
first argument. Do nothing, 'cause FFI_TYPE_VOID
|
|
||||||
is 0 */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* The structure is returned via some tricky
|
|
||||||
mechanism */
|
|
||||||
cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
|
|
||||||
cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
/* Do nothing, 'cause FFI_TYPE_VOID is 0 */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Low level routine for calling O32 functions */
|
|
||||||
extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
|
|
||||||
extended_cif *, unsigned,
|
|
||||||
unsigned, unsigned *, void (*)());
|
|
||||||
|
|
||||||
/* Low level routine for calling N32 functions */
|
|
||||||
extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
|
|
||||||
extended_cif *, unsigned,
|
|
||||||
unsigned, unsigned *, void (*)());
|
|
||||||
|
|
||||||
void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
if ((rvalue == NULL) &&
|
|
||||||
(cif->rtype->type == FFI_TYPE_STRUCT))
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
|
||||||
case FFI_O32:
|
|
||||||
ffi_call_O32(ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32
|
|
||||||
case FFI_N32:
|
|
||||||
ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
n32.S - Copyright (c) 1996, 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
MIPS 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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
/* Only build this code if we are compiling for n32 */
|
|
||||||
|
|
||||||
#if defined(FFI_MIPS_N32)
|
|
||||||
|
|
||||||
#define callback a0
|
|
||||||
#define bytes a2
|
|
||||||
#define flags a3
|
|
||||||
#define raddr a4
|
|
||||||
#define fn a5
|
|
||||||
|
|
||||||
#define SIZEOF_FRAME ( 8 * SIZEOF_ARG )
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 2
|
|
||||||
.globl ffi_call_N32
|
|
||||||
.ent ffi_call_N32
|
|
||||||
ffi_call_N32:
|
|
||||||
|
|
||||||
# Prologue
|
|
||||||
SUBU $sp, SIZEOF_FRAME # Frame size
|
|
||||||
REG_S $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Save frame pointer
|
|
||||||
REG_S ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp) # Save return address
|
|
||||||
move $fp, $sp
|
|
||||||
|
|
||||||
move t9, callback # callback function pointer
|
|
||||||
REG_S bytes, 2*SIZEOF_ARG($fp) # bytes
|
|
||||||
REG_S flags, 3*SIZEOF_ARG($fp) # flags
|
|
||||||
REG_S raddr, 4*SIZEOF_ARG($fp) # raddr
|
|
||||||
REG_S fn, 5*SIZEOF_ARG($fp) # fn
|
|
||||||
|
|
||||||
# Allocate at least 4 words in the argstack
|
|
||||||
move v0, bytes
|
|
||||||
bge bytes, 4 * SIZEOF_ARG, bigger
|
|
||||||
LI v0, 4 * SIZEOF_ARG
|
|
||||||
b sixteen
|
|
||||||
|
|
||||||
bigger:
|
|
||||||
ADDU t4, v0, 2 * SIZEOF_ARG -1 # make sure it is aligned
|
|
||||||
and v0, t4, -2 * SIZEOF_ARG # to a proper boundry.
|
|
||||||
|
|
||||||
sixteen:
|
|
||||||
SUBU $sp, $sp, v0 # move the stack pointer to reflect the
|
|
||||||
# arg space
|
|
||||||
|
|
||||||
ADDU a0, $sp, 0 # 4 * SIZEOF_ARG
|
|
||||||
ADDU a3, $fp, 3 * SIZEOF_ARG
|
|
||||||
|
|
||||||
# Call ffi_prep_args
|
|
||||||
jal t9
|
|
||||||
|
|
||||||
# ADDU $sp, $sp, 4 * SIZEOF_ARG # adjust $sp to new args
|
|
||||||
|
|
||||||
# Copy the stack pointer to t9
|
|
||||||
move t9, $sp
|
|
||||||
|
|
||||||
# Fix the stack if there are more than 8 64bit slots worth
|
|
||||||
# of arguments.
|
|
||||||
|
|
||||||
# Load the number of bytes
|
|
||||||
REG_L t6, 2*SIZEOF_ARG($fp)
|
|
||||||
|
|
||||||
# Is it bigger than 8 * SIZEOF_ARG?
|
|
||||||
dadd t7, $0, 8 * SIZEOF_ARG
|
|
||||||
dsub t8, t6, t7
|
|
||||||
bltz t8, loadregs
|
|
||||||
|
|
||||||
add t9, t9, t8
|
|
||||||
|
|
||||||
loadregs:
|
|
||||||
|
|
||||||
REG_L t4, 3*SIZEOF_ARG($fp) # load the flags word
|
|
||||||
add t6, t4, 0 # and copy it into t6
|
|
||||||
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg1_floatp
|
|
||||||
REG_L a0, 0*SIZEOF_ARG(t9)
|
|
||||||
b arg1_next
|
|
||||||
arg1_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg1_doublep
|
|
||||||
l.s $f12, 0*SIZEOF_ARG(t9)
|
|
||||||
b arg1_next
|
|
||||||
arg1_doublep:
|
|
||||||
l.d $f12, 0*SIZEOF_ARG(t9)
|
|
||||||
arg1_next:
|
|
||||||
|
|
||||||
add t4, t6, 0
|
|
||||||
SRL t4, 1*FFI_FLAG_BITS
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg2_floatp
|
|
||||||
REG_L a1, 1*SIZEOF_ARG(t9)
|
|
||||||
b arg2_next
|
|
||||||
arg2_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg2_doublep
|
|
||||||
l.s $f13, 1*SIZEOF_ARG(t9)
|
|
||||||
b arg2_next
|
|
||||||
arg2_doublep:
|
|
||||||
l.d $f13, 1*SIZEOF_ARG(t9)
|
|
||||||
arg2_next:
|
|
||||||
|
|
||||||
add t4, t6, 0
|
|
||||||
SRL t4, 2*FFI_FLAG_BITS
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg3_floatp
|
|
||||||
REG_L a2, 2*SIZEOF_ARG(t9)
|
|
||||||
b arg3_next
|
|
||||||
arg3_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg3_doublep
|
|
||||||
l.s $f14, 2*SIZEOF_ARG(t9)
|
|
||||||
b arg3_next
|
|
||||||
arg3_doublep:
|
|
||||||
l.d $f14, 2*SIZEOF_ARG(t9)
|
|
||||||
arg3_next:
|
|
||||||
|
|
||||||
add t4, t6, 0
|
|
||||||
SRL t4, 3*FFI_FLAG_BITS
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg4_floatp
|
|
||||||
REG_L a3, 3*SIZEOF_ARG(t9)
|
|
||||||
b arg4_next
|
|
||||||
arg4_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg4_doublep
|
|
||||||
l.s $f15, 3*SIZEOF_ARG(t9)
|
|
||||||
b arg4_next
|
|
||||||
arg4_doublep:
|
|
||||||
l.d $f15, 3*SIZEOF_ARG(t9)
|
|
||||||
arg4_next:
|
|
||||||
|
|
||||||
add t4, t6, 0
|
|
||||||
SRL t4, 4*FFI_FLAG_BITS
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg5_floatp
|
|
||||||
REG_L a4, 4*SIZEOF_ARG(t9)
|
|
||||||
b arg5_next
|
|
||||||
arg5_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg5_doublep
|
|
||||||
l.s $f16, 4*SIZEOF_ARG(t9)
|
|
||||||
b arg5_next
|
|
||||||
arg5_doublep:
|
|
||||||
l.d $f16, 4*SIZEOF_ARG(t9)
|
|
||||||
arg5_next:
|
|
||||||
|
|
||||||
add t4, t6, 0
|
|
||||||
SRL t4, 5*FFI_FLAG_BITS
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg6_floatp
|
|
||||||
REG_L a5, 5*SIZEOF_ARG(t9)
|
|
||||||
b arg6_next
|
|
||||||
arg6_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg6_doublep
|
|
||||||
l.s $f17, 5*SIZEOF_ARG(t9)
|
|
||||||
b arg6_next
|
|
||||||
arg6_doublep:
|
|
||||||
l.d $f17, 5*SIZEOF_ARG(t9)
|
|
||||||
arg6_next:
|
|
||||||
|
|
||||||
add t4, t6, 0
|
|
||||||
SRL t4, 6*FFI_FLAG_BITS
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg7_floatp
|
|
||||||
REG_L a6, 6*SIZEOF_ARG(t9)
|
|
||||||
b arg7_next
|
|
||||||
arg7_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg7_doublep
|
|
||||||
l.s $f18, 6*SIZEOF_ARG(t9)
|
|
||||||
b arg7_next
|
|
||||||
arg7_doublep:
|
|
||||||
l.d $f18, 6*SIZEOF_ARG(t9)
|
|
||||||
arg7_next:
|
|
||||||
|
|
||||||
add t4, t6, 0
|
|
||||||
SRL t4, 7*FFI_FLAG_BITS
|
|
||||||
and t4, ((1<<FFI_FLAG_BITS)-1)
|
|
||||||
bnez t4, arg8_floatp
|
|
||||||
REG_L a7, 7*SIZEOF_ARG(t9)
|
|
||||||
b arg8_next
|
|
||||||
arg8_floatp:
|
|
||||||
bne t4, FFI_TYPE_FLOAT, arg8_doublep
|
|
||||||
l.s $f19, 7*SIZEOF_ARG(t9)
|
|
||||||
b arg8_next
|
|
||||||
arg8_doublep:
|
|
||||||
l.d $f19, 7*SIZEOF_ARG(t9)
|
|
||||||
arg8_next:
|
|
||||||
|
|
||||||
callit:
|
|
||||||
# Load the function pointer
|
|
||||||
REG_L t9, 5*SIZEOF_ARG($fp)
|
|
||||||
|
|
||||||
# If the return value pointer is NULL, assume no return value.
|
|
||||||
REG_L t5, 4*SIZEOF_ARG($fp)
|
|
||||||
beqz t5, noretval
|
|
||||||
|
|
||||||
# Shift the return type flag over
|
|
||||||
SRL t6, 8*FFI_FLAG_BITS
|
|
||||||
|
|
||||||
bne t6, FFI_TYPE_INT, retfloat
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
REG_S v0, 0(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retfloat:
|
|
||||||
bne t6, FFI_TYPE_FLOAT, retdouble
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.s $f0, 0(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retdouble:
|
|
||||||
bne t6, FFI_TYPE_DOUBLE, retstruct_d
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.d $f0, 0(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_d:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_D, retstruct_f
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.d $f0, 0(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_f:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.s $f0, 0(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_d_d:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.d $f0, 0(t4)
|
|
||||||
s.d $f2, 8(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_f_f:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.s $f0, 0(t4)
|
|
||||||
s.s $f2, 4(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_d_f:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.d $f0, 0(t4)
|
|
||||||
s.s $f2, 8(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_f_d:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_FD, retstruct_small
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
s.s $f0, 0(t4)
|
|
||||||
s.d $f2, 8(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_small:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
REG_S v0, 0(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct_small2:
|
|
||||||
bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct
|
|
||||||
jal t9
|
|
||||||
REG_L t4, 4*SIZEOF_ARG($fp)
|
|
||||||
REG_S v0, 0(t4)
|
|
||||||
REG_S v1, 8(t4)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retstruct:
|
|
||||||
noretval:
|
|
||||||
jal t9
|
|
||||||
|
|
||||||
# Epilogue
|
|
||||||
epilogue:
|
|
||||||
move $sp, $fp
|
|
||||||
REG_L $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Restore frame pointer
|
|
||||||
REG_L ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp) # Restore return address
|
|
||||||
ADDU $sp, SIZEOF_FRAME # Fix stack pointer
|
|
||||||
j ra
|
|
||||||
|
|
||||||
.end ffi_call_N32
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
o32.S - Copyright (c) 1996, 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
MIPS 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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
/* Only build this code if we are compiling for o32 */
|
|
||||||
|
|
||||||
#if defined(FFI_MIPS_O32)
|
|
||||||
|
|
||||||
#define callback a0
|
|
||||||
#define bytes a2
|
|
||||||
#define flags a3
|
|
||||||
|
|
||||||
#define SIZEOF_FRAME ( 4 * SIZEOF_ARG + 2 * SIZEOF_ARG )
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 2
|
|
||||||
.globl ffi_call_O32
|
|
||||||
.ent ffi_call_O32
|
|
||||||
ffi_call_O32:
|
|
||||||
|
|
||||||
# Prologue
|
|
||||||
SUBU $sp, SIZEOF_FRAME # Frame size
|
|
||||||
REG_S $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Save frame pointer
|
|
||||||
REG_S ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp) # Save return address
|
|
||||||
move $fp, $sp
|
|
||||||
|
|
||||||
move t9, callback # callback function pointer
|
|
||||||
REG_S flags, SIZEOF_FRAME + 3*SIZEOF_ARG($fp) # flags
|
|
||||||
|
|
||||||
# Allocate at least 4 words in the argstack
|
|
||||||
move v0, bytes
|
|
||||||
bge bytes, 4 * SIZEOF_ARG, bigger
|
|
||||||
LI v0, 4 * SIZEOF_ARG
|
|
||||||
b sixteen
|
|
||||||
|
|
||||||
bigger:
|
|
||||||
ADDU t0, v0, 2 * SIZEOF_ARG -1 # make sure it is aligned
|
|
||||||
and v0, t0, -2 * SIZEOF_ARG # to an 8 byte boundry
|
|
||||||
|
|
||||||
sixteen:
|
|
||||||
SUBU $sp, $sp, v0 # move the stack pointer to reflect the
|
|
||||||
# arg space
|
|
||||||
|
|
||||||
ADDU a0, $sp, 4 * SIZEOF_ARG
|
|
||||||
ADDU a3, $fp, SIZEOF_FRAME + 3*SIZEOF_ARG
|
|
||||||
|
|
||||||
jal t9
|
|
||||||
|
|
||||||
REG_L t0, SIZEOF_FRAME + 3*SIZEOF_ARG($fp) # load the flags word
|
|
||||||
add t2, t0, 0 # and copy it into t2
|
|
||||||
|
|
||||||
and t0, ((1<<4)-1) # mask out the return type
|
|
||||||
SRL t2, 4 # shift our arg info
|
|
||||||
|
|
||||||
ADDU $sp, $sp, 4 * SIZEOF_ARG # adjust $sp to new args
|
|
||||||
|
|
||||||
bnez t0, pass_d # make it quick for int
|
|
||||||
REG_L a0, 0*SIZEOF_ARG($sp) # just go ahead and load the
|
|
||||||
REG_L a1, 1*SIZEOF_ARG($sp) # four regs.
|
|
||||||
REG_L a2, 2*SIZEOF_ARG($sp)
|
|
||||||
REG_L a3, 3*SIZEOF_ARG($sp)
|
|
||||||
b call_it
|
|
||||||
|
|
||||||
pass_d:
|
|
||||||
bne t0, FFI_ARGS_D, pass_f
|
|
||||||
l.d $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
|
|
||||||
REG_L a2, 2*SIZEOF_ARG($sp) # passing a double
|
|
||||||
REG_L a3, 3*SIZEOF_ARG($sp)
|
|
||||||
b call_it
|
|
||||||
|
|
||||||
pass_f:
|
|
||||||
bne t0, FFI_ARGS_F, pass_d_d
|
|
||||||
l.s $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
|
|
||||||
REG_L a1, 1*SIZEOF_ARG($sp) # passing a float
|
|
||||||
REG_L a2, 2*SIZEOF_ARG($sp)
|
|
||||||
REG_L a3, 3*SIZEOF_ARG($sp)
|
|
||||||
b call_it
|
|
||||||
|
|
||||||
pass_d_d:
|
|
||||||
bne t0, FFI_ARGS_DD, pass_f_f
|
|
||||||
l.d $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
|
|
||||||
l.d $f14, 2*SIZEOF_ARG($sp) # passing two doubles
|
|
||||||
b call_it
|
|
||||||
|
|
||||||
pass_f_f:
|
|
||||||
bne t0, FFI_ARGS_FF, pass_d_f
|
|
||||||
l.s $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
|
|
||||||
l.s $f14, 1*SIZEOF_ARG($sp) # passing two floats
|
|
||||||
REG_L a2, 2*SIZEOF_ARG($sp)
|
|
||||||
REG_L a3, 3*SIZEOF_ARG($sp)
|
|
||||||
b call_it
|
|
||||||
|
|
||||||
pass_d_f:
|
|
||||||
bne t0, FFI_ARGS_DF, pass_f_d
|
|
||||||
l.d $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
|
|
||||||
l.s $f14, 2*SIZEOF_ARG($sp) # passing double and float
|
|
||||||
REG_L a3, 3*SIZEOF_ARG($sp)
|
|
||||||
b call_it
|
|
||||||
|
|
||||||
pass_f_d:
|
|
||||||
# assume that the only other combination must be float then double
|
|
||||||
# bne t0, FFI_ARGS_F_D, call_it
|
|
||||||
l.s $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
|
|
||||||
l.d $f14, 2*SIZEOF_ARG($sp) # passing double and float
|
|
||||||
|
|
||||||
call_it:
|
|
||||||
# Load the function pointer
|
|
||||||
REG_L t9, SIZEOF_FRAME + 5*SIZEOF_ARG($fp)
|
|
||||||
|
|
||||||
# If the return value pointer is NULL, assume no return value.
|
|
||||||
REG_L t1, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
|
|
||||||
beqz t1, noretval
|
|
||||||
|
|
||||||
bne t2, FFI_TYPE_INT, retfloat
|
|
||||||
jal t9
|
|
||||||
REG_L t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
|
|
||||||
REG_S v0, 0(t0)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retfloat:
|
|
||||||
bne t2, FFI_TYPE_FLOAT, retdouble
|
|
||||||
jal t9
|
|
||||||
REG_L t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
|
|
||||||
s.s $f0, 0(t0)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
retdouble:
|
|
||||||
bne t2, FFI_TYPE_DOUBLE, noretval
|
|
||||||
jal t9
|
|
||||||
REG_L t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
|
|
||||||
s.d $f0, 0(t0)
|
|
||||||
b epilogue
|
|
||||||
|
|
||||||
noretval:
|
|
||||||
jal t9
|
|
||||||
|
|
||||||
# Epilogue
|
|
||||||
epilogue:
|
|
||||||
move $sp, $fp
|
|
||||||
REG_L $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Restore frame pointer
|
|
||||||
REG_L ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp) # Restore return address
|
|
||||||
ADDU $sp, SIZEOF_FRAME # Fix stack pointer
|
|
||||||
j ra
|
|
||||||
|
|
||||||
.end ffi_call_O32
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
asm.h - Copyright (c) 1998 Geoffrey Keating
|
|
||||||
|
|
||||||
PowerPC Assembly glue.
|
|
||||||
|
|
||||||
$Id: asm.h,v 1.1 1998/11/29 16:48:16 green Exp $
|
|
||||||
|
|
||||||
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 AUTHOR 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 ASM_GLOBAL_DIRECTIVE .globl
|
|
||||||
|
|
||||||
|
|
||||||
#define C_SYMBOL_NAME(name) name
|
|
||||||
/* Macro for a label. */
|
|
||||||
#ifdef __STDC__
|
|
||||||
#define C_LABEL(name) name##:
|
|
||||||
#else
|
|
||||||
#define C_LABEL(name) name/**/:
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* This seems to always be the case on PPC. */
|
|
||||||
#define ALIGNARG(log2) log2
|
|
||||||
/* For ELF we need the `.type' directive to make shared libs work right. */
|
|
||||||
#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
|
|
||||||
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
|
|
||||||
|
|
||||||
/* If compiled for profiling, call `_mcount' at the start of each function. */
|
|
||||||
#ifdef PROF
|
|
||||||
/* The mcount code relies on a the return address being on the stack
|
|
||||||
to locate our caller and so it can restore it; so store one just
|
|
||||||
for its benefit. */
|
|
||||||
#ifdef PIC
|
|
||||||
#define CALL_MCOUNT \
|
|
||||||
.pushsection; \
|
|
||||||
.section ".data"; \
|
|
||||||
.align ALIGNARG(2); \
|
|
||||||
0:.long 0; \
|
|
||||||
.previous; \
|
|
||||||
mflr %r0; \
|
|
||||||
stw %r0,4(%r1); \
|
|
||||||
bl _GLOBAL_OFFSET_TABLE_@local-4; \
|
|
||||||
mflr %r11; \
|
|
||||||
lwz %r0,0b@got(%r11); \
|
|
||||||
bl JUMPTARGET(_mcount);
|
|
||||||
#else /* PIC */
|
|
||||||
#define CALL_MCOUNT \
|
|
||||||
.section ".data"; \
|
|
||||||
.align ALIGNARG(2); \
|
|
||||||
0:.long 0; \
|
|
||||||
.previous; \
|
|
||||||
mflr %r0; \
|
|
||||||
lis %r11,0b@ha; \
|
|
||||||
stw %r0,4(%r1); \
|
|
||||||
addi %r0,%r11,0b@l; \
|
|
||||||
bl JUMPTARGET(_mcount);
|
|
||||||
#endif /* PIC */
|
|
||||||
#else /* PROF */
|
|
||||||
#define CALL_MCOUNT /* Do nothing. */
|
|
||||||
#endif /* PROF */
|
|
||||||
|
|
||||||
#define ENTRY(name) \
|
|
||||||
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
|
|
||||||
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
|
|
||||||
.align ALIGNARG(2); \
|
|
||||||
C_LABEL(name) \
|
|
||||||
CALL_MCOUNT
|
|
||||||
|
|
||||||
#define EALIGN_W_0 /* No words to insert. */
|
|
||||||
#define EALIGN_W_1 nop
|
|
||||||
#define EALIGN_W_2 nop;nop
|
|
||||||
#define EALIGN_W_3 nop;nop;nop
|
|
||||||
#define EALIGN_W_4 EALIGN_W_3;nop
|
|
||||||
#define EALIGN_W_5 EALIGN_W_4;nop
|
|
||||||
#define EALIGN_W_6 EALIGN_W_5;nop
|
|
||||||
#define EALIGN_W_7 EALIGN_W_6;nop
|
|
||||||
|
|
||||||
/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes
|
|
||||||
past a 2^align boundary. */
|
|
||||||
#ifdef PROF
|
|
||||||
#define EALIGN(name, alignt, words) \
|
|
||||||
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
|
|
||||||
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
|
|
||||||
.align ALIGNARG(2); \
|
|
||||||
C_LABEL(name) \
|
|
||||||
CALL_MCOUNT \
|
|
||||||
b 0f; \
|
|
||||||
.align ALIGNARG(alignt); \
|
|
||||||
EALIGN_W_##words; \
|
|
||||||
0:
|
|
||||||
#else /* PROF */
|
|
||||||
#define EALIGN(name, alignt, words) \
|
|
||||||
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
|
|
||||||
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
|
|
||||||
.align ALIGNARG(alignt); \
|
|
||||||
EALIGN_W_##words; \
|
|
||||||
C_LABEL(name)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define END(name) \
|
|
||||||
ASM_SIZE_DIRECTIVE(name)
|
|
||||||
|
|
||||||
#ifdef PIC
|
|
||||||
#define JUMPTARGET(name) name##@plt
|
|
||||||
#else
|
|
||||||
#define JUMPTARGET(name) name
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Local labels stripped out by the linker. */
|
|
||||||
#define L(x) .L##x
|
|
||||||
|
|
||||||
@@ -1,680 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 1998 Geoffrey Keating
|
|
||||||
|
|
||||||
PowerPC Foreign Function Interface
|
|
||||||
|
|
||||||
$Id: ffi.c,v 1.2 2001/04/09 00:58:37 green Exp $
|
|
||||||
|
|
||||||
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 AUTHOR 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 <stdio.h>
|
|
||||||
|
|
||||||
extern void ffi_closure_SYSV(void);
|
|
||||||
|
|
||||||
enum {
|
|
||||||
/* The assembly depends on these exact flags. */
|
|
||||||
FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
|
|
||||||
FLAG_RETURNS_FP = 1 << (31-29),
|
|
||||||
FLAG_RETURNS_64BITS = 1 << (31-28),
|
|
||||||
|
|
||||||
FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
|
|
||||||
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
|
|
||||||
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
|
|
||||||
FLAG_RETVAL_REFERENCE = 1 << (31- 4)
|
|
||||||
};
|
|
||||||
|
|
||||||
/* About the SYSV ABI. */
|
|
||||||
enum {
|
|
||||||
NUM_GPR_ARG_REGISTERS = 8,
|
|
||||||
NUM_FPR_ARG_REGISTERS = 8
|
|
||||||
};
|
|
||||||
enum { ASM_NEEDS_REGISTERS = 4 };
|
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space
|
|
||||||
has been allocated for the function's arguments.
|
|
||||||
|
|
||||||
The stack layout we want looks like this:
|
|
||||||
|
|
||||||
| Return address from ffi_call_SYSV 4bytes | higher addresses
|
|
||||||
|--------------------------------------------|
|
|
||||||
| Previous backchain pointer 4 | stack pointer here
|
|
||||||
|--------------------------------------------|<+ <<< on entry to
|
|
||||||
| Saved r28-r31 4*4 | | ffi_call_SYSV
|
|
||||||
|--------------------------------------------| |
|
|
||||||
| GPR registers r3-r10 8*4 | | ffi_call_SYSV
|
|
||||||
|--------------------------------------------| |
|
|
||||||
| FPR registers f1-f8 (optional) 8*8 | |
|
|
||||||
|--------------------------------------------| | stack |
|
|
||||||
| Space for copied structures | | grows |
|
|
||||||
|--------------------------------------------| | down V
|
|
||||||
| Parameters that didn't fit in registers | |
|
|
||||||
|--------------------------------------------| | lower addresses
|
|
||||||
| Space for callee's LR 4 | |
|
|
||||||
|--------------------------------------------| | stack pointer here
|
|
||||||
| Current backchain pointer 4 |-/ during
|
|
||||||
|--------------------------------------------| <<< ffi_call_SYSV
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*@-exportheader@*/
|
|
||||||
void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
|
|
||||||
/*@=exportheader@*/
|
|
||||||
{
|
|
||||||
const unsigned bytes = ecif->cif->bytes;
|
|
||||||
const unsigned flags = ecif->cif->flags;
|
|
||||||
|
|
||||||
/* 'stacktop' points at the previous backchain pointer. */
|
|
||||||
unsigned *const stacktop = stack + (ecif->cif->bytes / sizeof(unsigned));
|
|
||||||
|
|
||||||
/* 'gpr_base' points at the space for gpr3, and grows upwards as
|
|
||||||
we use GPR registers. */
|
|
||||||
unsigned *gpr_base = stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
|
|
||||||
int intarg_count = 0;
|
|
||||||
|
|
||||||
/* 'fpr_base' points at the space for fpr1, and grows upwards as
|
|
||||||
we use FPR registers. */
|
|
||||||
double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS;
|
|
||||||
int fparg_count = 0;
|
|
||||||
|
|
||||||
/* 'copy_space' grows down as we put structures in it. It should
|
|
||||||
stay 16-byte aligned. */
|
|
||||||
char *copy_space = ((flags & FLAG_FP_ARGUMENTS)
|
|
||||||
? (char *)fpr_base
|
|
||||||
: (char *)gpr_base);
|
|
||||||
|
|
||||||
/* 'next_arg' grows up as we put parameters in it. */
|
|
||||||
unsigned *next_arg = stack + 2;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
ffi_type **ptr;
|
|
||||||
double double_tmp;
|
|
||||||
void **p_argv;
|
|
||||||
size_t struct_copy_size;
|
|
||||||
unsigned gprvalue;
|
|
||||||
|
|
||||||
/* Check that everything starts aligned properly. */
|
|
||||||
FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
|
|
||||||
FFI_ASSERT(((unsigned)(char *)copy_space & 0xF) == 0);
|
|
||||||
FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
|
|
||||||
FFI_ASSERT((bytes & 0xF) == 0);
|
|
||||||
FFI_ASSERT(copy_space >= (char *)next_arg);
|
|
||||||
|
|
||||||
/* Deal with return values that are actually pass-by-reference. */
|
|
||||||
if (flags & FLAG_RETVAL_REFERENCE)
|
|
||||||
{
|
|
||||||
*gpr_base++ = (unsigned)(char *)ecif->rvalue;
|
|
||||||
intarg_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now for the arguments. */
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
|
|
||||||
i > 0;
|
|
||||||
i--, ptr++, p_argv++)
|
|
||||||
{
|
|
||||||
switch ((*ptr)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
if ((*ptr)->type == FFI_TYPE_FLOAT)
|
|
||||||
double_tmp = *(float *)*p_argv;
|
|
||||||
else
|
|
||||||
double_tmp = *(double *)*p_argv;
|
|
||||||
|
|
||||||
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
|
|
||||||
{
|
|
||||||
if (intarg_count%2 != 0)
|
|
||||||
{
|
|
||||||
intarg_count++;
|
|
||||||
next_arg++;
|
|
||||||
}
|
|
||||||
*(double *)next_arg = double_tmp;
|
|
||||||
next_arg += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*fpr_base++ = double_tmp;
|
|
||||||
fparg_count++;
|
|
||||||
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
|
|
||||||
intarg_count++;
|
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
|
|
||||||
{
|
|
||||||
if (intarg_count%2 != 0)
|
|
||||||
{
|
|
||||||
intarg_count++;
|
|
||||||
next_arg++;
|
|
||||||
}
|
|
||||||
*(long long *)next_arg = *(long long *)*p_argv;
|
|
||||||
next_arg += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* whoops: abi states only certain register pairs
|
|
||||||
* can be used for passing long long int
|
|
||||||
* specifically (r3,r4), (r5,r6), (r7,r8),
|
|
||||||
* (r9,r10) and if next arg is long long but
|
|
||||||
* not correct starting register of pair then skip
|
|
||||||
* until the proper starting register
|
|
||||||
*/
|
|
||||||
if (intarg_count%2 != 0)
|
|
||||||
{
|
|
||||||
intarg_count ++;
|
|
||||||
gpr_base++;
|
|
||||||
}
|
|
||||||
*(long long *)gpr_base = *(long long *)*p_argv;
|
|
||||||
gpr_base += 2;
|
|
||||||
}
|
|
||||||
intarg_count += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
#endif
|
|
||||||
struct_copy_size = ((*ptr)->size + 15) & ~0xF;
|
|
||||||
copy_space -= struct_copy_size;
|
|
||||||
memcpy(copy_space, (char *)*p_argv, (*ptr)->size);
|
|
||||||
|
|
||||||
gprvalue = (unsigned)copy_space;
|
|
||||||
|
|
||||||
FFI_ASSERT(copy_space > (char *)next_arg);
|
|
||||||
FFI_ASSERT(flags & FLAG_ARG_NEEDS_COPY);
|
|
||||||
goto putgpr;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
gprvalue = *(unsigned char *)*p_argv;
|
|
||||||
goto putgpr;
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
gprvalue = *(signed char *)*p_argv;
|
|
||||||
goto putgpr;
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
gprvalue = *(unsigned short *)*p_argv;
|
|
||||||
goto putgpr;
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
gprvalue = *(signed short *)*p_argv;
|
|
||||||
goto putgpr;
|
|
||||||
|
|
||||||
case FFI_TYPE_INT:
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
gprvalue = *(unsigned *)*p_argv;
|
|
||||||
putgpr:
|
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
|
|
||||||
*next_arg++ = gprvalue;
|
|
||||||
else
|
|
||||||
*gpr_base++ = gprvalue;
|
|
||||||
intarg_count++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that we didn't overrun the stack... */
|
|
||||||
FFI_ASSERT(copy_space >= (char *)next_arg);
|
|
||||||
FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
|
|
||||||
FFI_ASSERT((unsigned *)fpr_base
|
|
||||||
<= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
|
|
||||||
FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|
||||||
{
|
|
||||||
/* All this is for the SYSV ABI. */
|
|
||||||
int i;
|
|
||||||
ffi_type **ptr;
|
|
||||||
unsigned bytes;
|
|
||||||
int fparg_count = 0, intarg_count = 0;
|
|
||||||
unsigned flags = 0;
|
|
||||||
unsigned struct_copy_size = 0;
|
|
||||||
|
|
||||||
/* All the machine-independent calculation of cif->bytes will be wrong.
|
|
||||||
Redo the calculation for SYSV. */
|
|
||||||
|
|
||||||
/* Space for the frame pointer, callee's LR, and the asm's temp regs. */
|
|
||||||
bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof(int);
|
|
||||||
|
|
||||||
/* Space for the GPR registers. */
|
|
||||||
bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
|
|
||||||
|
|
||||||
/* Return value handling. The rules are as follows:
|
|
||||||
- 32-bit (or less) integer values are returned in gpr3;
|
|
||||||
- Structures of size <= 4 bytes also returned in gpr3;
|
|
||||||
- 64-bit integer values and structures between 5 and 8 bytes are returned
|
|
||||||
in gpr3 and gpr4;
|
|
||||||
- Single/double FP values are returned in fpr1;
|
|
||||||
- Larger structures and long double (if not equivalent to double) values
|
|
||||||
are allocated space and a pointer is passed as the first argument. */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
flags |= FLAG_RETURNS_64BITS;
|
|
||||||
/* Fall through. */
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
flags |= FLAG_RETURNS_FP;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
flags |= FLAG_RETURNS_64BITS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
if (cif->abi != FFI_GCC_SYSV)
|
|
||||||
if (cif->rtype->size <= 4)
|
|
||||||
break;
|
|
||||||
else if (cif->rtype->size <= 8)
|
|
||||||
{
|
|
||||||
flags |= FLAG_RETURNS_64BITS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* else fall through. */
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
#endif
|
|
||||||
intarg_count++;
|
|
||||||
flags |= FLAG_RETVAL_REFERENCE;
|
|
||||||
/* Fall through. */
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
flags |= FLAG_RETURNS_NOTHING;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* Returns 32-bit integer, or similar. Nothing to do here. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
|
|
||||||
first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
|
|
||||||
goes on the stack. Structures and long doubles (if not equivalent
|
|
||||||
to double) are passed as a pointer to a copy of the structure.
|
|
||||||
Stuff on the stack needs to keep proper alignment. */
|
|
||||||
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
|
|
||||||
{
|
|
||||||
switch ((*ptr)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
fparg_count++;
|
|
||||||
/* If this FP arg is going on the stack, it must be
|
|
||||||
8-byte-aligned. */
|
|
||||||
if (fparg_count > NUM_FPR_ARG_REGISTERS
|
|
||||||
&& intarg_count%2 != 0)
|
|
||||||
intarg_count++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
/* 'long long' arguments are passed as two words, but
|
|
||||||
either both words must fit in registers or both go
|
|
||||||
on the stack. If they go on the stack, they must
|
|
||||||
be 8-byte-aligned. */
|
|
||||||
if (intarg_count == NUM_GPR_ARG_REGISTERS-1
|
|
||||||
|| intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)
|
|
||||||
intarg_count++;
|
|
||||||
intarg_count += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
#endif
|
|
||||||
/* We must allocate space for a copy of these to enforce
|
|
||||||
pass-by-value. Pad the space up to a multiple of 16
|
|
||||||
bytes (the maximum alignment required for anything under
|
|
||||||
the SYSV ABI). */
|
|
||||||
struct_copy_size += ((*ptr)->size + 15) & ~0xF;
|
|
||||||
/* Fall through (allocate space for the pointer). */
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* Everything else is passed as a 4-byte word in a GPR, either
|
|
||||||
the object itself or a pointer to it. */
|
|
||||||
intarg_count++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fparg_count != 0)
|
|
||||||
flags |= FLAG_FP_ARGUMENTS;
|
|
||||||
if (intarg_count > 4)
|
|
||||||
flags |= FLAG_4_GPR_ARGUMENTS;
|
|
||||||
if (struct_copy_size != 0)
|
|
||||||
flags |= FLAG_ARG_NEEDS_COPY;
|
|
||||||
|
|
||||||
/* Space for the FPR registers, if needed. */
|
|
||||||
if (fparg_count != 0)
|
|
||||||
bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
|
|
||||||
|
|
||||||
/* Stack space. */
|
|
||||||
if (intarg_count > NUM_GPR_ARG_REGISTERS)
|
|
||||||
bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof(int);
|
|
||||||
if (fparg_count > NUM_FPR_ARG_REGISTERS)
|
|
||||||
bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof(double);
|
|
||||||
|
|
||||||
/* The stack space allocated needs to be a multiple of 16 bytes. */
|
|
||||||
bytes = (bytes + 15) & ~0xF;
|
|
||||||
|
|
||||||
/* Add in the space for the copied structures. */
|
|
||||||
bytes += struct_copy_size;
|
|
||||||
|
|
||||||
cif->flags = flags;
|
|
||||||
cif->bytes = bytes;
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*@-declundef@*/
|
|
||||||
/*@-exportheader@*/
|
|
||||||
extern void ffi_call_SYSV(/*@out@*/ extended_cif *,
|
|
||||||
unsigned, unsigned,
|
|
||||||
/*@out@*/ unsigned *,
|
|
||||||
void (*fn)());
|
|
||||||
/*@=declundef@*/
|
|
||||||
/*@=exportheader@*/
|
|
||||||
|
|
||||||
void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
|
||||||
void (*fn)(),
|
|
||||||
/*@out@*/ void *rvalue,
|
|
||||||
/*@dependent@*/ void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
if ((rvalue == NULL) &&
|
|
||||||
(cif->rtype->type == FFI_TYPE_STRUCT))
|
|
||||||
{
|
|
||||||
/*@-sysunrecog@*/
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
/*@=sysunrecog@*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_SYSV:
|
|
||||||
case FFI_GCC_SYSV:
|
|
||||||
/*@-usedef@*/
|
|
||||||
ffi_call_SYSV(&ecif, -cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
/*@=usedef@*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void flush_icache(char *, int);
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_closure (ffi_closure* closure,
|
|
||||||
ffi_cif* cif,
|
|
||||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
unsigned int *tramp;
|
|
||||||
|
|
||||||
FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
|
|
||||||
|
|
||||||
tramp = (unsigned int *) &closure->tramp[0];
|
|
||||||
tramp[0] = 0x7c0802a6; /* mflr r0 */
|
|
||||||
tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */
|
|
||||||
tramp[4] = 0x7d6802a6; /* mflr r11 */
|
|
||||||
tramp[5] = 0x7c0803a6; /* mtlr r0 */
|
|
||||||
tramp[6] = 0x800b0000; /* lwz r0,0(r11) */
|
|
||||||
tramp[7] = 0x816b0004; /* lwz r11,4(r11) */
|
|
||||||
tramp[8] = 0x7c0903a6; /* mtctr r0 */
|
|
||||||
tramp[9] = 0x4e800420; /* bctr */
|
|
||||||
*(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */
|
|
||||||
*(void **) &tramp[3] = (void *)closure; /* context */
|
|
||||||
|
|
||||||
closure->cif = cif;
|
|
||||||
closure->fun = fun;
|
|
||||||
closure->user_data = user_data;
|
|
||||||
|
|
||||||
/* Flush the icache. */
|
|
||||||
flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define MIN_CACHE_LINE_SIZE 8
|
|
||||||
|
|
||||||
static void flush_icache(char * addr1, int size)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char * addr;
|
|
||||||
for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
|
|
||||||
addr = addr1 + i;
|
|
||||||
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
|
|
||||||
}
|
|
||||||
addr = addr1 + size - 1;
|
|
||||||
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*,
|
|
||||||
unsigned long*, unsigned long*);
|
|
||||||
|
|
||||||
/* Basically the trampoline invokes ffi_closure_SYSV, and on
|
|
||||||
* entry, r11 holds the address of the closure.
|
|
||||||
* After storing the registers that could possibly contain
|
|
||||||
* parameters to be passed into the stack frame and setting
|
|
||||||
* up space for a return value, ffi_closure_SYSV invokes the
|
|
||||||
* following helper function to do most of the work
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
|
|
||||||
unsigned long * pgr, unsigned long * pfr,
|
|
||||||
unsigned long * pst)
|
|
||||||
{
|
|
||||||
/* rvalue is the pointer to space for return value in closure assembly */
|
|
||||||
/* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */
|
|
||||||
/* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */
|
|
||||||
/* pst is the pointer to outgoing parameter stack in original caller */
|
|
||||||
|
|
||||||
void ** avalue;
|
|
||||||
ffi_type ** arg_types;
|
|
||||||
long i, avn;
|
|
||||||
long nf; /* number of floating registers already used */
|
|
||||||
long ng; /* number of general registers already used */
|
|
||||||
ffi_cif * cif;
|
|
||||||
double temp;
|
|
||||||
|
|
||||||
cif = closure->cif;
|
|
||||||
avalue = alloca(cif->nargs * sizeof(void *));
|
|
||||||
|
|
||||||
nf = 0;
|
|
||||||
ng = 0;
|
|
||||||
|
|
||||||
/* Copy the caller's structure return value address so that the closure
|
|
||||||
returns the data directly to the caller. */
|
|
||||||
if (cif->rtype->type == FFI_TYPE_STRUCT)
|
|
||||||
{
|
|
||||||
rvalue = *pgr;
|
|
||||||
ng++;
|
|
||||||
pgr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
avn = cif->nargs;
|
|
||||||
arg_types = cif->arg_types;
|
|
||||||
|
|
||||||
/* Grab the addresses of the arguments from the stack frame. */
|
|
||||||
while (i < avn)
|
|
||||||
{
|
|
||||||
switch (arg_types[i]->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
/* there are 8 gpr registers used to pass values */
|
|
||||||
if (ng < 8) {
|
|
||||||
avalue[i] = (((char *)pgr)+3);
|
|
||||||
ng++;
|
|
||||||
pgr++;
|
|
||||||
} else {
|
|
||||||
avalue[i] = (((char *)pst)+3);
|
|
||||||
pst++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
/* there are 8 gpr registers used to pass values */
|
|
||||||
if (ng < 8) {
|
|
||||||
avalue[i] = (((char *)pgr)+2);
|
|
||||||
ng++;
|
|
||||||
pgr++;
|
|
||||||
} else {
|
|
||||||
avalue[i] = (((char *)pst)+2);
|
|
||||||
pst++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
/* there are 8 gpr registers used to pass values */
|
|
||||||
if (ng < 8) {
|
|
||||||
avalue[i] = pgr;
|
|
||||||
ng++;
|
|
||||||
pgr++;
|
|
||||||
} else {
|
|
||||||
avalue[i] = pst;
|
|
||||||
pst++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
/* passing long long ints are complex, they must
|
|
||||||
* be passed in suitable register pairs such as
|
|
||||||
* (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
|
|
||||||
* and if the entire pair aren't available then the outgoing
|
|
||||||
* parameter stack is used for both but an alignment of 8
|
|
||||||
* must will be kept. So we must either look in pgr
|
|
||||||
* or pst to find the correct address for this type
|
|
||||||
* of parameter.
|
|
||||||
*/
|
|
||||||
if (ng < 7) {
|
|
||||||
if (ng & 0x01) {
|
|
||||||
/* skip r4, r6, r8 as starting points */
|
|
||||||
ng++;
|
|
||||||
pgr++;
|
|
||||||
}
|
|
||||||
avalue[i] = pgr;
|
|
||||||
ng+=2;
|
|
||||||
pgr+=2;
|
|
||||||
} else {
|
|
||||||
if (((long)pst) & 4) pst++;
|
|
||||||
avalue[i] = pst;
|
|
||||||
pst+=2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
/* unfortunately float values are stored as doubles
|
|
||||||
* in the ffi_closure_SYSV code (since we don't check
|
|
||||||
* the type in that routine). This is also true
|
|
||||||
* of floats passed on the outgoing parameter stack.
|
|
||||||
* Also, on the outgoing stack all values are aligned
|
|
||||||
* to 8
|
|
||||||
*
|
|
||||||
* Don't you just love the simplicity of this ABI!
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* there are 8 64bit floating point registers */
|
|
||||||
|
|
||||||
if (nf < 8) {
|
|
||||||
temp = *(double*)pfr;
|
|
||||||
*(float*)pfr = (float)temp;
|
|
||||||
avalue[i] = pfr;
|
|
||||||
nf++;
|
|
||||||
pfr+=2;
|
|
||||||
} else {
|
|
||||||
/* FIXME? here we are really changing the values
|
|
||||||
* stored in the original calling routines outgoing
|
|
||||||
* parameter stack. This is probably a really
|
|
||||||
* naughty thing to do but...
|
|
||||||
*/
|
|
||||||
if (((long)pst) & 4) pst++;
|
|
||||||
temp = *(double*)pst;
|
|
||||||
*(float*)pst = (float)temp;
|
|
||||||
avalue[i] = pst;
|
|
||||||
nf++;
|
|
||||||
pst+=2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
/* On the outgoing stack all values are aligned to 8 */
|
|
||||||
/* there are 8 64bit floating point registers */
|
|
||||||
|
|
||||||
if (nf < 8) {
|
|
||||||
avalue[i] = pfr;
|
|
||||||
nf++;
|
|
||||||
pfr+=2;
|
|
||||||
} else {
|
|
||||||
if (((long)pst) & 4) pst++;
|
|
||||||
avalue[i] = pst;
|
|
||||||
nf++;
|
|
||||||
pst+=2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
(closure->fun) (cif, rvalue, avalue, closure->user_data);
|
|
||||||
|
|
||||||
/* Tell ffi_closure_osf how to perform return type promotions. */
|
|
||||||
return cif->rtype->type;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
#define LIBFFI_ASM
|
|
||||||
#include <powerpc/asm.h>
|
|
||||||
|
|
||||||
.globl ffi_closure_helper_SYSV
|
|
||||||
|
|
||||||
ENTRY(ffi_closure_SYSV)
|
|
||||||
stwu %r1,-144(%r1)
|
|
||||||
mflr %r0
|
|
||||||
stw %r31,140(%r1)
|
|
||||||
stw %r0,148(%r1)
|
|
||||||
|
|
||||||
# we want to build up an areas for the parameters passed
|
|
||||||
# in registers (both floating point and integer)
|
|
||||||
|
|
||||||
# so first save gpr 3 to gpr 10 (aligned to 4)
|
|
||||||
stw %r3, 16(%r1)
|
|
||||||
stw %r4, 20(%r1)
|
|
||||||
stw %r5, 24(%r1)
|
|
||||||
stw %r6, 28(%r1)
|
|
||||||
stw %r7, 32(%r1)
|
|
||||||
stw %r8, 36(%r1)
|
|
||||||
stw %r9, 40(%r1)
|
|
||||||
stw %r10,44(%r1)
|
|
||||||
|
|
||||||
# next save fpr 1 to fpr 8 (aligned to 8)
|
|
||||||
stfd %f1, 48(%r1)
|
|
||||||
stfd %f2, 56(%r1)
|
|
||||||
stfd %f3, 64(%r1)
|
|
||||||
stfd %f4, 72(%r1)
|
|
||||||
stfd %f5, 80(%r1)
|
|
||||||
stfd %f6, 88(%r1)
|
|
||||||
stfd %f7, 96(%r1)
|
|
||||||
stfd %f8, 104(%r1)
|
|
||||||
|
|
||||||
# set up registers for the routine that actually does the work
|
|
||||||
# get the context pointer from the trampoline
|
|
||||||
mr %r3,%r11
|
|
||||||
|
|
||||||
# now load up the pointer to the result storage
|
|
||||||
addi %r4,%r1,112
|
|
||||||
|
|
||||||
# now load up the pointer to the saved gpr registers
|
|
||||||
addi %r5,%r1,16
|
|
||||||
|
|
||||||
# now load up the pointer to the saved fpr registers */
|
|
||||||
addi %r6,%r1,48
|
|
||||||
|
|
||||||
# now load up the pointer to the outgoing parameter
|
|
||||||
# stack in the previous frame
|
|
||||||
# i.e. the previous frame pointer + 8
|
|
||||||
addi %r7,%r1,152
|
|
||||||
|
|
||||||
# make the call
|
|
||||||
bl JUMPTARGET(ffi_closure_helper_SYSV)
|
|
||||||
|
|
||||||
# now r3 contains the return type
|
|
||||||
# so use it to look up in a table
|
|
||||||
# so we know how to deal with each type
|
|
||||||
|
|
||||||
# look up the proper starting point in table
|
|
||||||
# by using return type as offset
|
|
||||||
addi %r5,%r1,112 # get pointer to results area
|
|
||||||
addis %r4,0,.L60@ha # get address of jump table
|
|
||||||
addi %r4,%r4,.L60@l
|
|
||||||
slwi %r3,%r3,2 # now multiply return type by 4
|
|
||||||
lwzx %r3,%r4,%r3 # get the contents of that table value
|
|
||||||
add %r3,%r3,%r4 # add contents of table to table address
|
|
||||||
mtctr %r3
|
|
||||||
bctr # jump to it
|
|
||||||
.align 2
|
|
||||||
.L60:
|
|
||||||
.long .L44-.L60 # FFI_TYPE_VOID
|
|
||||||
.long .L50-.L60 # FFI_TYPE_INT
|
|
||||||
.long .L47-.L60 # FFI_TYPE_FLOAT
|
|
||||||
.long .L46-.L60 # FFI_TYPE_DOUBLE
|
|
||||||
.long .L46-.L60 # FFI_TYPE_LONGDOUBLE
|
|
||||||
.long .L56-.L60 # FFI_TYPE_UINT8
|
|
||||||
.long .L55-.L60 # FFI_TYPE_SINT8
|
|
||||||
.long .L58-.L60 # FFI_TYPE_UINT16
|
|
||||||
.long .L57-.L60 # FFI_TYPE_SINT16
|
|
||||||
.long .L50-.L60 # FFI_TYPE_UINT32
|
|
||||||
.long .L50-.L60 # FFI_TYPE_SINT32
|
|
||||||
.long .L48-.L60 # FFI_TYPE_UINT64
|
|
||||||
.long .L48-.L60 # FFI_TYPE_SINT64
|
|
||||||
.long .L44-.L60 # FFI_TYPE_STRUCT
|
|
||||||
.long .L50-.L60 # FFI_TYPE_POINTER
|
|
||||||
|
|
||||||
|
|
||||||
# case double
|
|
||||||
.L46:
|
|
||||||
lfd %f1,0(%r5)
|
|
||||||
b .L44
|
|
||||||
|
|
||||||
# case float
|
|
||||||
.L47:
|
|
||||||
lfs %f1,0(%r5)
|
|
||||||
b .L44
|
|
||||||
|
|
||||||
# case long long
|
|
||||||
.L48:
|
|
||||||
lwz %r3,0(%r5)
|
|
||||||
lwz %r4,4(%r5)
|
|
||||||
b .L44
|
|
||||||
|
|
||||||
# case default / int32 / pointer
|
|
||||||
.L50:
|
|
||||||
lwz %r3,0(%r5)
|
|
||||||
b .L44
|
|
||||||
|
|
||||||
# case signed int8
|
|
||||||
.L55:
|
|
||||||
addi %r5,%r5,3
|
|
||||||
lbz %r3,0(%r5)
|
|
||||||
extsb %r3,%r3
|
|
||||||
b .L44
|
|
||||||
|
|
||||||
# case unsigned int8
|
|
||||||
.L56:
|
|
||||||
addi %r5,%r5,3
|
|
||||||
lbz %r3,0(%r5)
|
|
||||||
b .L44
|
|
||||||
|
|
||||||
# case signed int16
|
|
||||||
.L57:
|
|
||||||
addi %r5,%r5,2
|
|
||||||
lhz %r3,0(%r5)
|
|
||||||
extsh %r3,%r3
|
|
||||||
b .L44
|
|
||||||
|
|
||||||
#case unsigned int16
|
|
||||||
.L58:
|
|
||||||
addi %r5,%r5,2
|
|
||||||
lhz %r3,0(%r5)
|
|
||||||
|
|
||||||
# case void / done
|
|
||||||
.L44:
|
|
||||||
|
|
||||||
lwz %r11,0(%r1)
|
|
||||||
lwz %r0,4(%r11)
|
|
||||||
mtlr %r0
|
|
||||||
lwz %r31,-4(%r11)
|
|
||||||
mr %r1,%r11
|
|
||||||
blr
|
|
||||||
END(ffi_closure_SYSV)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
sysv.h - Copyright (c) 1998 Geoffrey Keating
|
|
||||||
|
|
||||||
PowerPC Assembly glue.
|
|
||||||
|
|
||||||
$Id: sysv.S,v 1.1 1998/11/29 16:48:16 green Exp $
|
|
||||||
|
|
||||||
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 AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
#include <powerpc/asm.h>
|
|
||||||
|
|
||||||
.globl ffi_prep_args
|
|
||||||
ENTRY(ffi_call_SYSV)
|
|
||||||
/* Save the old stack pointer as AP. */
|
|
||||||
mr %r8,%r1
|
|
||||||
|
|
||||||
/* Allocate the stack space we need. */
|
|
||||||
stwux %r1,%r1,%r4
|
|
||||||
/* Save registers we use. */
|
|
||||||
mflr %r9
|
|
||||||
stw %r28,-16(%r8)
|
|
||||||
stw %r29,-12(%r8)
|
|
||||||
stw %r30, -8(%r8)
|
|
||||||
stw %r31, -4(%r8)
|
|
||||||
stw %r9, 4(%r8)
|
|
||||||
|
|
||||||
/* Save arguments over call... */
|
|
||||||
mr %r31,%r5 /* flags, */
|
|
||||||
mr %r30,%r6 /* rvalue, */
|
|
||||||
mr %r29,%r7 /* function address, */
|
|
||||||
mr %r28,%r8 /* our AP. */
|
|
||||||
|
|
||||||
/* Call ffi_prep_args. */
|
|
||||||
mr %r4,%r1
|
|
||||||
bl JUMPTARGET(ffi_prep_args)
|
|
||||||
|
|
||||||
/* Now do the call. */
|
|
||||||
/* Set up cr1 with bits 4-7 of the flags. */
|
|
||||||
mtcrf 0x40,%r31
|
|
||||||
/* Get the address to call into CTR. */
|
|
||||||
mtctr %r29
|
|
||||||
/* Load all those argument registers. */
|
|
||||||
lwz %r3,-16-(8*4)(%r28)
|
|
||||||
lwz %r4,-16-(7*4)(%r28)
|
|
||||||
lwz %r5,-16-(6*4)(%r28)
|
|
||||||
lwz %r6,-16-(5*4)(%r28)
|
|
||||||
bf- 5,1f
|
|
||||||
nop
|
|
||||||
lwz %r7,-16-(4*4)(%r28)
|
|
||||||
lwz %r8,-16-(3*4)(%r28)
|
|
||||||
lwz %r9,-16-(2*4)(%r28)
|
|
||||||
lwz %r10,-16-(1*4)(%r28)
|
|
||||||
nop
|
|
||||||
1:
|
|
||||||
|
|
||||||
/* Load all the FP registers. */
|
|
||||||
bf- 6,2f
|
|
||||||
lfd %f1,-16-(8*4)-(8*8)(%r28)
|
|
||||||
lfd %f2,-16-(8*4)-(7*8)(%r28)
|
|
||||||
lfd %f3,-16-(8*4)-(6*8)(%r28)
|
|
||||||
lfd %f4,-16-(8*4)-(5*8)(%r28)
|
|
||||||
nop
|
|
||||||
lfd %f5,-16-(8*4)-(4*8)(%r28)
|
|
||||||
lfd %f6,-16-(8*4)-(3*8)(%r28)
|
|
||||||
lfd %f7,-16-(8*4)-(2*8)(%r28)
|
|
||||||
lfd %f8,-16-(8*4)-(1*8)(%r28)
|
|
||||||
2:
|
|
||||||
|
|
||||||
/* Make the call. */
|
|
||||||
bctrl
|
|
||||||
|
|
||||||
/* Now, deal with the return value. */
|
|
||||||
mtcrf 0x01,%r31
|
|
||||||
bt- 30,L(done_return_value)
|
|
||||||
bt- 29,L(fp_return_value)
|
|
||||||
stw %r3,0(%r30)
|
|
||||||
bf+ 28,L(done_return_value)
|
|
||||||
stw %r4,4(%r30)
|
|
||||||
/* Fall through... */
|
|
||||||
|
|
||||||
L(done_return_value):
|
|
||||||
/* Restore the registers we used and return. */
|
|
||||||
lwz %r9, 4(%r28)
|
|
||||||
lwz %r31, -4(%r28)
|
|
||||||
mtlr %r9
|
|
||||||
lwz %r30, -8(%r28)
|
|
||||||
lwz %r29,-12(%r28)
|
|
||||||
lwz %r28,-16(%r28)
|
|
||||||
lwz %r1,0(%r1)
|
|
||||||
blr
|
|
||||||
|
|
||||||
L(fp_return_value):
|
|
||||||
bf 28,L(float_return_value)
|
|
||||||
stfd %f1,0(%r30)
|
|
||||||
b L(done_return_value)
|
|
||||||
L(float_return_value):
|
|
||||||
stfs %f1,0(%r30)
|
|
||||||
b L(done_return_value)
|
|
||||||
END(ffi_call_SYSV)
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
prep_cif.c - Copyright (c) 1996, 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
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 RED HAT 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>
|
|
||||||
|
|
||||||
|
|
||||||
/* Round up to SIZEOF_ARG. */
|
|
||||||
|
|
||||||
#define STACK_ARG_SIZE(x) ALIGN(x, SIZEOF_ARG)
|
|
||||||
|
|
||||||
/* Perform machine independent initialization of aggregate type
|
|
||||||
specifications. */
|
|
||||||
|
|
||||||
static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg)
|
|
||||||
{
|
|
||||||
ffi_type **ptr;
|
|
||||||
|
|
||||||
FFI_ASSERT(arg != NULL);
|
|
||||||
|
|
||||||
/*@-usedef@*/
|
|
||||||
|
|
||||||
FFI_ASSERT(arg->elements != NULL);
|
|
||||||
FFI_ASSERT(arg->size == 0);
|
|
||||||
FFI_ASSERT(arg->alignment == 0);
|
|
||||||
|
|
||||||
ptr = &(arg->elements[0]);
|
|
||||||
|
|
||||||
while ((*ptr) != NULL)
|
|
||||||
{
|
|
||||||
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
|
|
||||||
return FFI_BAD_TYPEDEF;
|
|
||||||
|
|
||||||
/* Perform a sanity check on the argument type */
|
|
||||||
FFI_ASSERT(ffi_type_test((*ptr)));
|
|
||||||
|
|
||||||
arg->size = ALIGN(arg->size, (*ptr)->alignment);
|
|
||||||
arg->size += (*ptr)->size;
|
|
||||||
|
|
||||||
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
|
|
||||||
arg->alignment : (*ptr)->alignment;
|
|
||||||
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg->size == 0)
|
|
||||||
return FFI_BAD_TYPEDEF;
|
|
||||||
else
|
|
||||||
return FFI_OK;
|
|
||||||
|
|
||||||
/*@=usedef@*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform machine independent ffi_cif preparation, then call
|
|
||||||
machine dependent routine. */
|
|
||||||
|
|
||||||
ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
|
|
||||||
ffi_abi abi, unsigned int nargs,
|
|
||||||
/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype,
|
|
||||||
/*@dependent@*/ ffi_type **atypes)
|
|
||||||
{
|
|
||||||
unsigned bytes = 0;
|
|
||||||
unsigned int i;
|
|
||||||
ffi_type **ptr;
|
|
||||||
|
|
||||||
FFI_ASSERT(cif != NULL);
|
|
||||||
FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi < FFI_LAST_ABI));
|
|
||||||
|
|
||||||
cif->abi = abi;
|
|
||||||
cif->arg_types = atypes;
|
|
||||||
cif->nargs = nargs;
|
|
||||||
cif->rtype = rtype;
|
|
||||||
|
|
||||||
cif->flags = 0;
|
|
||||||
|
|
||||||
/* Initialize the return type if necessary */
|
|
||||||
/*@-usedef@*/
|
|
||||||
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
|
|
||||||
return FFI_BAD_TYPEDEF;
|
|
||||||
/*@=usedef@*/
|
|
||||||
|
|
||||||
/* Perform a sanity check on the return type */
|
|
||||||
FFI_ASSERT(ffi_type_test(cif->rtype));
|
|
||||||
|
|
||||||
#ifndef M68K
|
|
||||||
/* 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
|
|
||||||
)
|
|
||||||
bytes = STACK_ARG_SIZE(sizeof(void*));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
|
|
||||||
{
|
|
||||||
/* Perform a sanity check on the argument type */
|
|
||||||
FFI_ASSERT(ffi_type_test(*ptr));
|
|
||||||
|
|
||||||
/* Initialize any uninitialized aggregate type definitions */
|
|
||||||
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
|
|
||||||
return FFI_BAD_TYPEDEF;
|
|
||||||
|
|
||||||
#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)
|
|
||||||
bytes = ALIGN(bytes, (*ptr)->alignment);
|
|
||||||
|
|
||||||
bytes += STACK_ARG_SIZE((*ptr)->size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cif->bytes = bytes;
|
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
|
||||||
return ffi_prep_cif_machdep(cif);
|
|
||||||
}
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
raw_api.c - Copyright (c) 1999 Cygnus Solutions
|
|
||||||
|
|
||||||
Author: Kresten Krab Thorup <krab@gnu.org>
|
|
||||||
|
|
||||||
$Id $
|
|
||||||
|
|
||||||
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 RED HAT 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.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* This file defines generic functions for use with the raw api. */
|
|
||||||
|
|
||||||
#include <ffi.h>
|
|
||||||
#include <ffi_common.h>
|
|
||||||
|
|
||||||
#if !FFI_NO_RAW_API
|
|
||||||
|
|
||||||
size_t
|
|
||||||
ffi_raw_size (ffi_cif *cif)
|
|
||||||
{
|
|
||||||
size_t result = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ffi_type **at = cif->arg_types;
|
|
||||||
|
|
||||||
for (i = cif->nargs-1; i >= 0; i--, at++)
|
|
||||||
{
|
|
||||||
#if !FFI_NO_STRUCTS
|
|
||||||
if ((*at)->type == FFI_TYPE_STRUCT)
|
|
||||||
result += ALIGN (sizeof (void*), SIZEOF_ARG);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
result += ALIGN ((*at)->size, SIZEOF_ARG);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
ffi_type **tp = cif->arg_types;
|
|
||||||
|
|
||||||
#if WORDS_BIGENDIAN
|
|
||||||
|
|
||||||
for (i = 0; i < cif->nargs; i++, tp++, args++)
|
|
||||||
{
|
|
||||||
switch ((*tp)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
*args = (void*) ((char*)(raw++) + SIZEOF_ARG - 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
*args = (void*) ((char*)(raw++) + SIZEOF_ARG - 2);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if SIZEOF_ARG >= 4
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
*args = (void*) ((char*)(raw++) + SIZEOF_ARG - 4);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !FFI_NO_STRUCTS
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
*args = (raw++)->ptr;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
*args = (void*) &(raw++)->ptr;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
*args = raw;
|
|
||||||
raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* WORDS_BIGENDIAN */
|
|
||||||
|
|
||||||
#if !PDP
|
|
||||||
|
|
||||||
/* then assume little endian */
|
|
||||||
for (i = 0; i < cif->nargs; i++, tp++, args++)
|
|
||||||
{
|
|
||||||
#if !FFI_NO_STRUCTS
|
|
||||||
if ((*tp)->type == FFI_TYPE_STRUCT)
|
|
||||||
{
|
|
||||||
*args = (raw++)->ptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
*args = (void*) raw;
|
|
||||||
raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "pdp endian not supported"
|
|
||||||
#endif /* ! PDP */
|
|
||||||
|
|
||||||
#endif /* WORDS_BIGENDIAN */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
ffi_type **tp = cif->arg_types;
|
|
||||||
|
|
||||||
for (i = 0; i < cif->nargs; i++, tp++, args++)
|
|
||||||
{
|
|
||||||
switch ((*tp)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
(raw++)->uint = *(UINT8*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
(raw++)->sint = *(SINT8*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
(raw++)->uint = *(UINT16*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
(raw++)->sint = *(SINT16*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if SIZEOF_ARG >= 4
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
(raw++)->uint = *(UINT32*) (*args);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
(raw++)->sint = *(SINT32*) (*args);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !FFI_NO_STRUCTS
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
(raw++)->ptr = *args;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
(raw++)->ptr = **(void***) args;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
|
|
||||||
raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !FFI_NATIVE_RAW_API
|
|
||||||
|
|
||||||
|
|
||||||
/* This is a generic definition of ffi_raw_call, to be used if the
|
|
||||||
* native system does not provide a machine-specific implementation.
|
|
||||||
* Having this, allows code to be written for the raw API, without
|
|
||||||
* the need for system-specific code to handle input in that format;
|
|
||||||
* these following couple of functions will handle the translation forth
|
|
||||||
* and back automatically. */
|
|
||||||
|
|
||||||
void ffi_raw_call (/*@dependent@*/ ffi_cif *cif,
|
|
||||||
void (*fn)(),
|
|
||||||
/*@out@*/ void *rvalue,
|
|
||||||
/*@dependent@*/ ffi_raw *raw)
|
|
||||||
{
|
|
||||||
void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
|
|
||||||
ffi_raw_to_ptrarray (cif, raw, avalue);
|
|
||||||
ffi_call (cif, fn, rvalue, avalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FFI_CLOSURES /* base system provides closures */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_translate_args (ffi_cif *cif, void *rvalue,
|
|
||||||
void **avalue, void *user_data)
|
|
||||||
{
|
|
||||||
ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
|
|
||||||
ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
|
|
||||||
|
|
||||||
ffi_ptrarray_to_raw (cif, avalue, raw);
|
|
||||||
(*cl->fun) (cif, rvalue, raw, cl->user_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Again, here is the generic version of ffi_prep_raw_closure, which
|
|
||||||
* will install an intermediate "hub" for translation of arguments from
|
|
||||||
* the pointer-array format, to the raw format */
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_raw_closure (ffi_raw_closure* cl,
|
|
||||||
ffi_cif *cif,
|
|
||||||
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
ffi_status status;
|
|
||||||
|
|
||||||
status = ffi_prep_closure ((ffi_closure*) cl,
|
|
||||||
cif,
|
|
||||||
&ffi_translate_args,
|
|
||||||
(void*)cl);
|
|
||||||
if (status == FFI_OK)
|
|
||||||
{
|
|
||||||
cl->fun = fun;
|
|
||||||
cl->user_data = user_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* FFI_CLOSURES */
|
|
||||||
#endif /* !FFI_NATIVE_RAW_API */
|
|
||||||
#endif /* !FFI_NO_RAW_API */
|
|
||||||
@@ -1,589 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 2000 Software AG
|
|
||||||
|
|
||||||
S390 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 AUTHOR 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.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
/*====================================================================*/
|
|
||||||
/* Includes */
|
|
||||||
/* -------- */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
#include <ffi.h>
|
|
||||||
#include <ffi_common.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/*====================== End of Includes =============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* Defines */
|
|
||||||
/* ------- */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
#define MAX_GPRARGS 5 /* Max. no. of GPR available */
|
|
||||||
#define MAX_FPRARGS 2 /* Max. no. of FPR available */
|
|
||||||
|
|
||||||
#define STR_GPR 1 /* Structure will fit in 1 or 2 GPR */
|
|
||||||
#define STR_FPR 2 /* Structure will fit in a FPR */
|
|
||||||
#define STR_STACK 3 /* Structure needs to go on stack */
|
|
||||||
|
|
||||||
/*===================== End of Defines ===============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* Types */
|
|
||||||
/* ----- */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
typedef struct stackLayout
|
|
||||||
{
|
|
||||||
int *backChain;
|
|
||||||
int *endOfStack;
|
|
||||||
int glue[2];
|
|
||||||
int scratch[2];
|
|
||||||
int gprArgs[MAX_GPRARGS];
|
|
||||||
int notUsed;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
float f;
|
|
||||||
double d;
|
|
||||||
} fprArgs[MAX_FPRARGS];
|
|
||||||
int unUsed[8];
|
|
||||||
int outArgs[100];
|
|
||||||
} stackLayout;
|
|
||||||
|
|
||||||
/*======================== End of Types ==============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* Prototypes */
|
|
||||||
/* ---------- */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
void ffi_prep_args(stackLayout *, extended_cif *);
|
|
||||||
static int ffi_check_struct(ffi_type *, unsigned int *);
|
|
||||||
static void ffi_insert_int(int, stackLayout *, int *, int *);
|
|
||||||
static void ffi_insert_int64(long long, stackLayout *, int *, int *);
|
|
||||||
static void ffi_insert_double(double, stackLayout *, int *, int *);
|
|
||||||
|
|
||||||
/*====================== End of Prototypes ===========================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* Externals */
|
|
||||||
/* --------- */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
extern void ffi_call_SYSV(void (*)(stackLayout *, extended_cif *),
|
|
||||||
extended_cif *,
|
|
||||||
unsigned, unsigned,
|
|
||||||
unsigned *,
|
|
||||||
void (*fn)());
|
|
||||||
|
|
||||||
/*====================== End of Externals ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_check_struct. */
|
|
||||||
/* */
|
|
||||||
/* Function - Determine if a structure can be passed within a */
|
|
||||||
/* general or floating point register. */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
int
|
|
||||||
ffi_check_struct(ffi_type *arg, unsigned int *strFlags)
|
|
||||||
{
|
|
||||||
ffi_type *element;
|
|
||||||
int i_Element;
|
|
||||||
|
|
||||||
for (i_Element = 0; arg->elements[i_Element]; i_Element++) {
|
|
||||||
element = arg->elements[i_Element];
|
|
||||||
switch (element->type) {
|
|
||||||
case FFI_TYPE_DOUBLE :
|
|
||||||
*strFlags |= STR_FPR;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT :
|
|
||||||
*strFlags |= ffi_check_struct(element, strFlags);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default :
|
|
||||||
*strFlags |= STR_GPR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (*strFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_insert_int. */
|
|
||||||
/* */
|
|
||||||
/* Function - Insert an integer parameter in a register if there are */
|
|
||||||
/* spares else on the stack. */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_insert_int(int gprValue, stackLayout *stack,
|
|
||||||
int *intArgC, int *outArgC)
|
|
||||||
{
|
|
||||||
if (*intArgC < MAX_GPRARGS) {
|
|
||||||
stack->gprArgs[*intArgC] = gprValue;
|
|
||||||
*intArgC += 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
stack->outArgs[*outArgC++] = gprValue;
|
|
||||||
*outArgC += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_insert_int64. */
|
|
||||||
/* */
|
|
||||||
/* Function - Insert a long long parameter in registers if there are */
|
|
||||||
/* spares else on the stack. */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_insert_int64(long long llngValue, stackLayout *stack,
|
|
||||||
int *intArgC, int *outArgC)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (*intArgC < (MAX_GPRARGS-1)) {
|
|
||||||
memcpy(&stack->gprArgs[*intArgC],
|
|
||||||
&llngValue, sizeof(long long));
|
|
||||||
*intArgC += 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy(&stack->outArgs[*outArgC],
|
|
||||||
&llngValue, sizeof(long long));
|
|
||||||
*outArgC += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_insert_double. */
|
|
||||||
/* */
|
|
||||||
/* Function - Insert a double parameter in a FP register if there is */
|
|
||||||
/* a spare else on the stack. */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_insert_double(double dblValue, stackLayout *stack,
|
|
||||||
int *fprArgC, int *outArgC)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (*fprArgC < MAX_FPRARGS) {
|
|
||||||
stack->fprArgs[*fprArgC].d = dblValue;
|
|
||||||
*fprArgC += 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy(&stack->outArgs[*outArgC],
|
|
||||||
&dblValue,sizeof(double));
|
|
||||||
*outArgC += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_prep_args. */
|
|
||||||
/* */
|
|
||||||
/* Function - Prepare parameters for call to function. */
|
|
||||||
/* */
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space */
|
|
||||||
/* has been allocated for the function's arguments. */
|
|
||||||
/* */
|
|
||||||
/* The stack layout we want looks like this: */
|
|
||||||
/* *------------------------------------------------------------* */
|
|
||||||
/* | 0 | Back chain (a 0 here signifies end of back chain) | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 4 | EOS (end of stack, not used on Linux for S390) | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 8 | Glue used in other linkage formats | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 12 | Glue used in other linkage formats | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 16 | Scratch area | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 20 | Scratch area | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 24 | GPR parameter register 1 | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 28 | GPR parameter register 2 | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 32 | GPR parameter register 3 | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 36 | GPR parameter register 4 | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 40 | GPR parameter register 5 | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 44 | Unused | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 48 | FPR parameter register 1 | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 56 | FPR parameter register 2 | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 64 | Unused | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 96 | Outgoing args (length x) | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 96+x | Copy area for structures (length y) | */
|
|
||||||
/* +--------+---------------------------------------------------+ */
|
|
||||||
/* | 96+x+y | Possible stack alignment | */
|
|
||||||
/* *------------------------------------------------------------* */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_prep_args(stackLayout *stack, extended_cif *ecif)
|
|
||||||
{
|
|
||||||
const unsigned bytes = ecif->cif->bytes;
|
|
||||||
const unsigned flags = ecif->cif->flags;
|
|
||||||
|
|
||||||
/*----------------------------------------------------------*/
|
|
||||||
/* Pointer to the copy area on stack for structures */
|
|
||||||
/*----------------------------------------------------------*/
|
|
||||||
char *copySpace = (char *) stack + bytes + sizeof(stackLayout);
|
|
||||||
|
|
||||||
/*----------------------------------------------------------*/
|
|
||||||
/* Count of general and floating point register usage */
|
|
||||||
/*----------------------------------------------------------*/
|
|
||||||
int intArgC = 0,
|
|
||||||
fprArgC = 0,
|
|
||||||
outArgC = 0;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
ffi_type **ptr;
|
|
||||||
void **p_argv;
|
|
||||||
size_t structCopySize;
|
|
||||||
unsigned gprValue, strFlags = 0;
|
|
||||||
unsigned long long llngValue;
|
|
||||||
double dblValue;
|
|
||||||
|
|
||||||
/* Now for the arguments. */
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
|
||||||
/* If we returning a structure then we set the first parameter register */
|
|
||||||
/* to the address of where we are returning this structure */
|
|
||||||
/*----------------------------------------------------------------------*/
|
|
||||||
if (flags == FFI_TYPE_STRUCT)
|
|
||||||
stack->gprArgs[intArgC++] = (int) ecif->rvalue;
|
|
||||||
|
|
||||||
for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
|
|
||||||
i > 0;
|
|
||||||
i--, ptr++, p_argv++)
|
|
||||||
{
|
|
||||||
switch ((*ptr)->type) {
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
if (fprArgC < MAX_FPRARGS)
|
|
||||||
stack->fprArgs[fprArgC++].f = *(float *) *p_argv;
|
|
||||||
else
|
|
||||||
stack->outArgs[outArgC++] = *(int *) *p_argv;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
dblValue = *(double *) *p_argv;
|
|
||||||
ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
llngValue = *(unsigned long long *) *p_argv;
|
|
||||||
ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
gprValue = *(unsigned char *)*p_argv;
|
|
||||||
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
gprValue = *(signed char *)*p_argv;
|
|
||||||
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
gprValue = *(unsigned short *)*p_argv;
|
|
||||||
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
gprValue = *(signed short *)*p_argv;
|
|
||||||
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
/*--------------------------------------------------*/
|
|
||||||
/* If structure > 8 bytes then it goes on the stack */
|
|
||||||
/*--------------------------------------------------*/
|
|
||||||
if (((*ptr)->size > 8) ||
|
|
||||||
((*ptr)->size > 4 &&
|
|
||||||
(*ptr)->size < 8))
|
|
||||||
strFlags = STR_STACK;
|
|
||||||
else
|
|
||||||
strFlags = ffi_check_struct((ffi_type *) *ptr, &strFlags);
|
|
||||||
|
|
||||||
switch (strFlags) {
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
/* Structure that will fit in one or two GPR */
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
case STR_GPR :
|
|
||||||
if ((*ptr)->size <= 4) {
|
|
||||||
gprValue = *(unsigned int *) *p_argv;
|
|
||||||
gprValue = gprValue >> ((4 - (*ptr)->size) * 8);
|
|
||||||
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
llngValue = *(unsigned long long *) *p_argv;
|
|
||||||
ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
/* Structure that will fit in one FPR */
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
case STR_FPR :
|
|
||||||
dblValue = *(double *) *p_argv;
|
|
||||||
ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
/* Structure that must be copied to stack */
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
default :
|
|
||||||
structCopySize = (((*ptr)->size + 15) & ~0xF);
|
|
||||||
copySpace -= structCopySize;
|
|
||||||
memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
|
|
||||||
gprValue = (unsigned) copySpace;
|
|
||||||
if (intArgC < MAX_GPRARGS)
|
|
||||||
stack->gprArgs[intArgC++] = gprValue;
|
|
||||||
else
|
|
||||||
stack->outArgs[outArgC++] = gprValue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
structCopySize = (((*ptr)->size + 15) & ~0xF);
|
|
||||||
copySpace -= structCopySize;
|
|
||||||
memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
|
|
||||||
gprValue = (unsigned) copySpace;
|
|
||||||
if (intArgC < MAX_GPRARGS)
|
|
||||||
stack->gprArgs[intArgC++] = gprValue;
|
|
||||||
else
|
|
||||||
stack->outArgs[outArgC++] = gprValue;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case FFI_TYPE_INT:
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
gprValue = *(unsigned *)*p_argv;
|
|
||||||
if (intArgC < MAX_GPRARGS)
|
|
||||||
stack->gprArgs[intArgC++] = gprValue;
|
|
||||||
else
|
|
||||||
stack->outArgs[outArgC++] = gprValue;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_prep_cif_machdep. */
|
|
||||||
/* */
|
|
||||||
/* Function - Perform machine dependent CIF processing. */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
ffi_type **ptr;
|
|
||||||
unsigned bytes;
|
|
||||||
int fpArgC = 0,
|
|
||||||
intArgC = 0;
|
|
||||||
unsigned flags = 0;
|
|
||||||
unsigned structCopySize = 0;
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
/* Extra space required in stack for overflow parameters. */
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
bytes = 0;
|
|
||||||
|
|
||||||
/*--------------------------------------------------------*/
|
|
||||||
/* Return value handling. The rules are as follows: */
|
|
||||||
/* - 32-bit (or less) integer values are returned in gpr2 */
|
|
||||||
/* - Structures are returned as pointers in gpr2 */
|
|
||||||
/* - 64-bit integer values are returned in gpr2 and 3 */
|
|
||||||
/* - Single/double FP values are returned in fpr0 */
|
|
||||||
/*--------------------------------------------------------*/
|
|
||||||
flags = cif->rtype->type;
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* The first MAX_GPRARGS words of integer arguments, and the */
|
|
||||||
/* first MAX_FPRARGS floating point arguments, go in registers; the rest */
|
|
||||||
/* goes on the stack. Structures and long doubles (if not equivalent */
|
|
||||||
/* to double) are passed as a pointer to a copy of the structure. */
|
|
||||||
/* Stuff on the stack needs to keep proper alignment. */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
|
|
||||||
{
|
|
||||||
switch ((*ptr)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
fpArgC++;
|
|
||||||
if (fpArgC > MAX_FPRARGS && intArgC%2 != 0)
|
|
||||||
intArgC++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
/* 'long long' arguments are passed as two words, but */
|
|
||||||
/* either both words must fit in registers or both go */
|
|
||||||
/* on the stack. If they go on the stack, they must */
|
|
||||||
/* be 8-byte-aligned. */
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
if ((intArgC == MAX_GPRARGS-1) ||
|
|
||||||
(intArgC >= MAX_GPRARGS) &&
|
|
||||||
(intArgC%2 != 0))
|
|
||||||
intArgC++;
|
|
||||||
intArgC += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
#endif
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
/* We must allocate space for a copy of these to */
|
|
||||||
/* enforce pass-by-value. Pad the space up to a */
|
|
||||||
/* multiple of 16 bytes (the maximum alignment */
|
|
||||||
/* required for anything under the SYSV ABI). */
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
structCopySize += ((*ptr)->size + 15) & ~0xF;
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
/* Fall through (allocate space for the pointer). */
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
|
|
||||||
default:
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
/* Everything else is passed as a 4-byte word in a */
|
|
||||||
/* GPR either the object itself or a pointer to it. */
|
|
||||||
/*----------------------------------------------------*/
|
|
||||||
intArgC++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
/* Stack space. */
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
if (intArgC > MAX_GPRARGS)
|
|
||||||
bytes += (intArgC - MAX_GPRARGS) * sizeof(int);
|
|
||||||
if (fpArgC > MAX_FPRARGS)
|
|
||||||
bytes += (fpArgC - MAX_FPRARGS) * sizeof(double);
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
/* The stack space allocated needs to be a multiple of 16 bytes. */
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
bytes = (bytes + 15) & ~0xF;
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
/* Add in the space for the copied structures. */
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
bytes += structCopySize;
|
|
||||||
|
|
||||||
cif->flags = flags;
|
|
||||||
cif->bytes = bytes;
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_call. */
|
|
||||||
/* */
|
|
||||||
/* Function - Call the FFI routine. */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_call(ffi_cif *cif,
|
|
||||||
void (*fn)(),
|
|
||||||
void *rvalue,
|
|
||||||
void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
/*-----------------------------------------------------------------*/
|
|
||||||
if ((rvalue == NULL) &&
|
|
||||||
(cif->rtype->type == FFI_TYPE_STRUCT))
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_SYSV:
|
|
||||||
ffi_call_SYSV(ffi_prep_args,
|
|
||||||
&ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
sysv.S - Copyright (c) 2000 Software AG
|
|
||||||
|
|
||||||
S390 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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
#ifdef HAVE_MACHINE_ASM_H
|
|
||||||
#include <machine/asm.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
# r2: ffi_prep_args
|
|
||||||
# r3: &ecif
|
|
||||||
# r4: cif->bytes
|
|
||||||
# r5: fig->flags
|
|
||||||
# r6: ecif.rvalue
|
|
||||||
# sp+0: fn
|
|
||||||
|
|
||||||
# This assumes we are using gas.
|
|
||||||
.globl ffi_call_SYSV
|
|
||||||
.type ffi_call_SYSV,%function
|
|
||||||
ffi_call_SYSV:
|
|
||||||
# Save registers
|
|
||||||
stm %r7,%r15,28(%r15)
|
|
||||||
l %r7,96(%r15) # Get A(fn)
|
|
||||||
lr %r0,%r15
|
|
||||||
ahi %r15,-128 # Make room for my args
|
|
||||||
st %r0,0(%r15) # Set backchain
|
|
||||||
lr %r11,%r15 # Establish my stack register
|
|
||||||
sr %r15,%r4 # Make room for fn args
|
|
||||||
ahi %r15,-96 # Make room for new frame
|
|
||||||
lr %r10,%r15 # Establish stack build area
|
|
||||||
ahi %r15,-96 # Stack for next call
|
|
||||||
lr %r1,%r7
|
|
||||||
stm %r2,%r7,96(%r11) # Save args on my stack
|
|
||||||
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# move first 3 parameters in registers
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
lr %r9,%r2 # r9: &ffi_prep_args
|
|
||||||
lr %r2,%r10 # Parm 1: &stack Parm 2: &ecif
|
|
||||||
basr %r14,%r9 # call ffi_prep_args
|
|
||||||
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# load first 5 parameter registers
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
lm %r2,%r6,24(%r10)
|
|
||||||
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# load fp parameter registers
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
ld %f0,48(%r10)
|
|
||||||
ld %f2,56(%r10)
|
|
||||||
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# call function
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
lr %r15,%r10 # Set new stack
|
|
||||||
l %r9,116(%r11) # Get &fn
|
|
||||||
basr %r14,%r9 # Call function
|
|
||||||
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# On return:
|
|
||||||
# r2: Return value (r3: Return value + 4 for long long)
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# If the return value pointer is NULL, assume no return value.
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
icm %r6,15,112(%r11)
|
|
||||||
jz .Lepilogue
|
|
||||||
|
|
||||||
l %r5,108(%r11) # Get return type
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# return INT
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
chi %r5,FFI_TYPE_INT
|
|
||||||
jne .Lchk64
|
|
||||||
|
|
||||||
st %r2,0(%r6)
|
|
||||||
j .Lepilogue
|
|
||||||
|
|
||||||
.Lchk64:
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# return LONG LONG (signed/unsigned)
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
chi %r5,FFI_TYPE_UINT64
|
|
||||||
je .LdoLongLong
|
|
||||||
|
|
||||||
chi %r5,FFI_TYPE_SINT64
|
|
||||||
jne .LchkFloat
|
|
||||||
|
|
||||||
.LdoLongLong:
|
|
||||||
stm %r2,%r3,0(%r6)
|
|
||||||
j .Lepilogue
|
|
||||||
|
|
||||||
.LchkFloat:
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# return FLOAT
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
chi %r5,FFI_TYPE_FLOAT
|
|
||||||
jne .LchkDouble
|
|
||||||
|
|
||||||
std %f0,0(%r6)
|
|
||||||
j .Lepilogue
|
|
||||||
|
|
||||||
.LchkDouble:
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# return DOUBLE or LONGDOUBLE
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
chi %r5,FFI_TYPE_DOUBLE
|
|
||||||
jne .LchkStruct
|
|
||||||
|
|
||||||
std %f0,0(%r6)
|
|
||||||
std %f2,8(%r6)
|
|
||||||
j .Lepilogue
|
|
||||||
|
|
||||||
.LchkStruct:
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# Structure - rvalue already set as sent as 1st parm to routine
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
chi %r5,FFI_TYPE_STRUCT
|
|
||||||
je .Lepilogue
|
|
||||||
|
|
||||||
.Ldefault:
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
# return a pointer
|
|
||||||
#------------------------------------------------------------------
|
|
||||||
st %r2,0(%r6)
|
|
||||||
j .Lepilogue
|
|
||||||
|
|
||||||
.Lepilogue:
|
|
||||||
l %r15,0(%r11)
|
|
||||||
l %r4,56(%r15)
|
|
||||||
lm %r7,%r15,28(%r15)
|
|
||||||
br %r4
|
|
||||||
|
|
||||||
.ffi_call_SYSV_end:
|
|
||||||
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
|
|
||||||
@@ -1,422 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 1996 Cygnus Solutions
|
|
||||||
|
|
||||||
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 CYGNUS SOLUTIONS 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>
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
int tmp;
|
|
||||||
int avn;
|
|
||||||
void **p_argv;
|
|
||||||
char *argp;
|
|
||||||
ffi_type **p_arg;
|
|
||||||
|
|
||||||
tmp = 0;
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
avn = ecif->cif->nargs;
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
|
|
||||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
|
||||||
i && avn;
|
|
||||||
i--, p_arg++)
|
|
||||||
{
|
|
||||||
size_t z;
|
|
||||||
|
|
||||||
if (avn)
|
|
||||||
{
|
|
||||||
avn--;
|
|
||||||
if ((*p_arg)->type == FFI_TYPE_STRUCT
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE
|
|
||||||
#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;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
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;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
if (cif->abi != FFI_V9)
|
|
||||||
{
|
|
||||||
cif->flags = FFI_TYPE_SINT64;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
default:
|
|
||||||
cif->flags = FFI_TYPE_INT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ffi_V9_return_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
|
|
||||||
{
|
|
||||||
ffi_type **ptr = &arg->elements[0];
|
|
||||||
|
|
||||||
while (*ptr != NULL)
|
|
||||||
{
|
|
||||||
if (off & ((*ptr)->alignment - 1))
|
|
||||||
off = ALIGN(off, (*ptr)->alignment);
|
|
||||||
|
|
||||||
switch ((*ptr)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
off = ffi_V9_return_struct(*ptr, off, ret, intg, flt);
|
|
||||||
break;
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
#endif
|
|
||||||
memcpy(ret + off, flt + off, (*ptr)->size);
|
|
||||||
off += (*ptr)->size;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
memcpy(ret + off, intg + off, (*ptr)->size);
|
|
||||||
off += (*ptr)->size;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
return off;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int ffi_call_V8(void *, extended_cif *, unsigned,
|
|
||||||
unsigned, unsigned *, void (*fn)());
|
|
||||||
extern int ffi_call_V9(void *, extended_cif *, unsigned,
|
|
||||||
unsigned, unsigned *, void (*fn)());
|
|
||||||
|
|
||||||
void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
void *rval = rvalue;
|
|
||||||
|
|
||||||
ecif.cif = cif;
|
|
||||||
ecif.avalue = avalue;
|
|
||||||
|
|
||||||
/* If the return value is a struct and we don't have a return */
|
|
||||||
/* value address then we need to make one */
|
|
||||||
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
if (cif->rtype->type == FFI_TYPE_STRUCT)
|
|
||||||
{
|
|
||||||
if (cif->rtype->size <= 32)
|
|
||||||
rval = alloca(64);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rval = NULL;
|
|
||||||
if (rvalue == NULL)
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_V8:
|
|
||||||
#ifdef SPARC64
|
|
||||||
/* We don't yet support calling 32bit code from 64bit */
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
#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_return_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
v8.S - Copyright (c) 1996, 1997 Cygnus Solutions
|
|
||||||
|
|
||||||
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
#define STACKFRAME 96 /* Minimum stack framesize for SPARC */
|
|
||||||
#define ARGS (64+4) /* Offset of register area in frame */
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 8
|
|
||||||
.globl ffi_call_V8
|
|
||||||
.globl _ffi_call_V8
|
|
||||||
|
|
||||||
ffi_call_V8:
|
|
||||||
_ffi_call_V8:
|
|
||||||
save %sp, -STACKFRAME, %sp
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
mov %l0, %o0 ! call routine to set up frame
|
|
||||||
call %i0
|
|
||||||
mov %i1, %o1 ! (delay)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
! If the return value pointer is NULL, assume no return value.
|
|
||||||
tst %i4
|
|
||||||
bz done
|
|
||||||
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_SINT64
|
|
||||||
be longlong
|
|
||||||
|
|
||||||
cmp %i3, FFI_TYPE_DOUBLE
|
|
||||||
bne done
|
|
||||||
nop
|
|
||||||
st %f0, [%i4+0]
|
|
||||||
st %f1, [%i4+4]
|
|
||||||
|
|
||||||
done:
|
|
||||||
ret
|
|
||||||
restore
|
|
||||||
|
|
||||||
longlong:
|
|
||||||
st %o0, [%i4+0]
|
|
||||||
st %o1, [%i4+4]
|
|
||||||
ret
|
|
||||||
restore
|
|
||||||
|
|
||||||
.ffi_call_V8_end:
|
|
||||||
.size ffi_call_V8,.ffi_call_V8_end-ffi_call_V8
|
|
||||||
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
v9.S - Copyright (c) 2000 Cygnus Solutions
|
|
||||||
|
|
||||||
Sparc 64bit 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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.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 128 /* Minimum stack framesize for SPARC */
|
|
||||||
#define STACK_BIAS 2047
|
|
||||||
#define ARGS (128) /* Offset of register area in frame */
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 8
|
|
||||||
.globl ffi_call_V9
|
|
||||||
.globl _ffi_call_V9
|
|
||||||
|
|
||||||
ffi_call_V9:
|
|
||||||
_ffi_call_V9:
|
|
||||||
save %sp, -STACKFRAME, %sp
|
|
||||||
|
|
||||||
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 %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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
! If the return value pointer is NULL, assume no return value.
|
|
||||||
brz,pn %i4, done
|
|
||||||
nop
|
|
||||||
|
|
||||||
cmp %i3, FFI_TYPE_INT
|
|
||||||
be,a,pt %icc, done
|
|
||||||
stx %o0, [%i4] ! (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
|
|
||||||
nop
|
|
||||||
std %f0, [%i4+0]
|
|
||||||
std %f2, [%i4+8]
|
|
||||||
|
|
||||||
done: ret
|
|
||||||
restore
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
.ffi_call_V9_end:
|
|
||||||
.size ffi_call_V9,.ffi_call_V9_end-ffi_call_V9
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
types.c - Copyright (c) 1996, 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
Predefined ffi_types needed by libffi.
|
|
||||||
|
|
||||||
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 RED HAT 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>
|
|
||||||
|
|
||||||
/* Type definitions */
|
|
||||||
|
|
||||||
#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL }
|
|
||||||
#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e }
|
|
||||||
|
|
||||||
/* Size and alignment are fake here. They must not be 0. */
|
|
||||||
FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID);
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
|
|
||||||
|
|
||||||
#if defined ALPHA || defined SPARC64
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef X86
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
|
|
||||||
|
|
||||||
#elif defined X86_WIN32
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
|
|
||||||
|
|
||||||
#elif defined ARM
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
|
|
||||||
|
|
||||||
#elif defined M68K
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef X86
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
|
|
||||||
|
|
||||||
#elif defined X86_WIN32
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
|
|
||||||
|
|
||||||
#elif defined ARM
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE);
|
|
||||||
|
|
||||||
#elif defined M68K
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
|
|
||||||
|
|
||||||
#elif defined SPARC
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
|
|
||||||
|
|
||||||
#ifdef SPARC64
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
|
|
||||||
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,508 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
ffi.c - Copyright (c) 1996, 1998, 1999 Cygnus Solutions
|
|
||||||
|
|
||||||
x86 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 CYGNUS SOLUTIONS 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>
|
|
||||||
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space
|
|
||||||
has been allocated for the function's arguments */
|
|
||||||
|
|
||||||
/*@-exportheader@*/
|
|
||||||
void ffi_prep_args(char *stack, extended_cif *ecif)
|
|
||||||
/*@=exportheader@*/
|
|
||||||
{
|
|
||||||
register unsigned int i;
|
|
||||||
register int tmp;
|
|
||||||
register unsigned int avn;
|
|
||||||
register void **p_argv;
|
|
||||||
register char *argp;
|
|
||||||
register ffi_type **p_arg;
|
|
||||||
|
|
||||||
tmp = 0;
|
|
||||||
argp = stack;
|
|
||||||
|
|
||||||
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) {
|
|
||||||
*(void **) argp = ecif->rvalue;
|
|
||||||
argp += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
avn = ecif->cif->nargs;
|
|
||||||
p_argv = ecif->avalue;
|
|
||||||
|
|
||||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
|
||||||
(i != 0) && (avn != 0);
|
|
||||||
i--, p_arg++)
|
|
||||||
{
|
|
||||||
size_t z;
|
|
||||||
|
|
||||||
/* Align if necessary */
|
|
||||||
if (((*p_arg)->alignment - 1) & (unsigned) argp) {
|
|
||||||
argp = (char *) ALIGN(argp, (*p_arg)->alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avn != 0)
|
|
||||||
{
|
|
||||||
avn--;
|
|
||||||
z = (*p_arg)->size;
|
|
||||||
if (z < sizeof(int))
|
|
||||||
{
|
|
||||||
z = sizeof(int);
|
|
||||||
switch ((*p_arg)->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
*(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(argp, *p_argv, z);
|
|
||||||
}
|
|
||||||
p_argv++;
|
|
||||||
argp += z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|
||||||
{
|
|
||||||
/* Set the return type flag */
|
|
||||||
switch (cif->rtype->type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_VOID:
|
|
||||||
case FFI_TYPE_STRUCT:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
|
||||||
cif->flags = (unsigned) cif->rtype->type;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
cif->flags = FFI_TYPE_SINT64;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
cif->flags = FFI_TYPE_INT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*@-declundef@*/
|
|
||||||
/*@-exportheader@*/
|
|
||||||
extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
|
|
||||||
/*@out@*/ extended_cif *,
|
|
||||||
unsigned, unsigned,
|
|
||||||
/*@out@*/ unsigned *,
|
|
||||||
void (*fn)());
|
|
||||||
/*@=declundef@*/
|
|
||||||
/*@=exportheader@*/
|
|
||||||
|
|
||||||
void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
|
||||||
void (*fn)(),
|
|
||||||
/*@out@*/ void *rvalue,
|
|
||||||
/*@dependent@*/ void **avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
if ((rvalue == NULL) &&
|
|
||||||
(cif->rtype->type == FFI_TYPE_STRUCT))
|
|
||||||
{
|
|
||||||
/*@-sysunrecog@*/
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
/*@=sysunrecog@*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_SYSV:
|
|
||||||
/*@-usedef@*/
|
|
||||||
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
/*@=usedef@*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** private members **/
|
|
||||||
|
|
||||||
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
|
|
||||||
void** args, ffi_cif* cif);
|
|
||||||
static void ffi_closure_SYSV ();
|
|
||||||
static void ffi_closure_raw_SYSV ();
|
|
||||||
|
|
||||||
/* This function is jumped to by the trampoline, on entry, %ecx (a
|
|
||||||
* caller-save register) holds the address of the closure.
|
|
||||||
* Clearly, this requires __GNUC__, so perhaps we should translate this
|
|
||||||
* into an assembly file if this is to be distributed with ffi.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_closure_SYSV ()
|
|
||||||
{
|
|
||||||
// this is our return value storage
|
|
||||||
long double res;
|
|
||||||
|
|
||||||
// our various things...
|
|
||||||
void *args;
|
|
||||||
ffi_cif *cif;
|
|
||||||
void **arg_area;
|
|
||||||
ffi_closure *closure;
|
|
||||||
unsigned short rtype;
|
|
||||||
void *resp = (void*)&res;
|
|
||||||
|
|
||||||
/* grab the trampoline context pointer */
|
|
||||||
asm ("movl %%ecx,%0" : "=r" (closure));
|
|
||||||
|
|
||||||
cif = closure->cif;
|
|
||||||
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
|
||||||
asm ("leal 8(%%ebp),%0" : "=q" (args));
|
|
||||||
|
|
||||||
/* this call will initialize ARG_AREA, such that each
|
|
||||||
* element in that array points to the corresponding
|
|
||||||
* value on the stack; and if the function returns
|
|
||||||
* a structure, it will re-set RESP to point to the
|
|
||||||
* structure return address. */
|
|
||||||
|
|
||||||
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
|
|
||||||
|
|
||||||
(closure->fun) (cif, resp, arg_area, closure->user_data);
|
|
||||||
|
|
||||||
rtype = cif->flags;
|
|
||||||
|
|
||||||
/* now, do a generic return based on the value of rtype */
|
|
||||||
if (rtype == FFI_TYPE_INT)
|
|
||||||
{
|
|
||||||
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_FLOAT)
|
|
||||||
{
|
|
||||||
asm ("flds (%0)" : : "r" (resp) : "st" );
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_DOUBLE)
|
|
||||||
{
|
|
||||||
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_LONGDOUBLE)
|
|
||||||
{
|
|
||||||
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_SINT64)
|
|
||||||
{
|
|
||||||
asm ("movl 0(%0),%%eax;"
|
|
||||||
"movl 4(%0),%%edx"
|
|
||||||
: : "r"(resp)
|
|
||||||
: "eax", "edx");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*@-exportheader@*/
|
|
||||||
static void
|
|
||||||
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
|
||||||
void **avalue, ffi_cif *cif)
|
|
||||||
/*@=exportheader@*/
|
|
||||||
{
|
|
||||||
register unsigned int i;
|
|
||||||
register int tmp;
|
|
||||||
register unsigned int avn;
|
|
||||||
register void **p_argv;
|
|
||||||
register char *argp;
|
|
||||||
register ffi_type **p_arg;
|
|
||||||
|
|
||||||
tmp = 0;
|
|
||||||
argp = stack;
|
|
||||||
|
|
||||||
if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
|
|
||||||
*rvalue = *(void **) argp;
|
|
||||||
argp += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
avn = cif->nargs;
|
|
||||||
p_argv = avalue;
|
|
||||||
|
|
||||||
for (i = cif->nargs, p_arg = cif->arg_types;
|
|
||||||
(i != 0) && (avn != 0);
|
|
||||||
i--, p_arg++)
|
|
||||||
{
|
|
||||||
size_t z;
|
|
||||||
|
|
||||||
/* Align if necessary */
|
|
||||||
if (((*p_arg)->alignment - 1) & (unsigned) argp) {
|
|
||||||
argp = (char *) ALIGN(argp, (*p_arg)->alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avn != 0)
|
|
||||||
{
|
|
||||||
avn--;
|
|
||||||
z = (*p_arg)->size;
|
|
||||||
|
|
||||||
/* because we're little endian, this is
|
|
||||||
what it turns into. */
|
|
||||||
|
|
||||||
*p_argv = (void*) argp;
|
|
||||||
|
|
||||||
p_argv++;
|
|
||||||
argp += z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
|
|
||||||
|
|
||||||
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
|
|
||||||
({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
|
|
||||||
unsigned int __fun = (unsigned int)(FUN); \
|
|
||||||
unsigned int __ctx = (unsigned int)(CTX); \
|
|
||||||
unsigned int __dis = __fun - ((unsigned int) __tramp + 10); \
|
|
||||||
*(unsigned char*) &__tramp[0] = 0xb9; \
|
|
||||||
*(unsigned int*) &__tramp[1] = __ctx; \
|
|
||||||
*(unsigned char*) &__tramp[5] = 0xe9; \
|
|
||||||
*(unsigned int*) &__tramp[6] = __dis; \
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
/* the cif must already be prep'ed */
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_closure (ffi_closure* closure,
|
|
||||||
ffi_cif* cif,
|
|
||||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
FFI_ASSERT (cif->abi == FFI_SYSV);
|
|
||||||
|
|
||||||
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
|
|
||||||
&ffi_closure_SYSV, \
|
|
||||||
(void*)closure);
|
|
||||||
|
|
||||||
closure->cif = cif;
|
|
||||||
closure->user_data = user_data;
|
|
||||||
closure->fun = fun;
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------- Native raw API support -------------------------------- */
|
|
||||||
|
|
||||||
#if !FFI_NO_RAW_API
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_closure_raw_SYSV ()
|
|
||||||
{
|
|
||||||
// this is our return value storage
|
|
||||||
long double res;
|
|
||||||
|
|
||||||
// our various things...
|
|
||||||
void *args;
|
|
||||||
ffi_raw *raw_args;
|
|
||||||
ffi_cif *cif;
|
|
||||||
ffi_raw_closure *closure;
|
|
||||||
unsigned short rtype;
|
|
||||||
void *resp = (void*)&res;
|
|
||||||
|
|
||||||
/* grab the trampoline context pointer */
|
|
||||||
asm ("movl %%ecx,%0" : "=r" (closure));
|
|
||||||
|
|
||||||
/* take the argument pointer */
|
|
||||||
asm ("leal 8(%%ebp),%0" : "=q" (args));
|
|
||||||
|
|
||||||
/* get the cif */
|
|
||||||
cif = closure->cif;
|
|
||||||
|
|
||||||
/* the SYSV/X86 abi matches the RAW API exactly, well.. almost */
|
|
||||||
raw_args = (ffi_raw*) args;
|
|
||||||
|
|
||||||
(closure->fun) (cif, resp, raw_args, closure->user_data);
|
|
||||||
|
|
||||||
rtype = cif->flags;
|
|
||||||
|
|
||||||
/* now, do a generic return based on the value of rtype */
|
|
||||||
if (rtype == FFI_TYPE_INT)
|
|
||||||
{
|
|
||||||
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_FLOAT)
|
|
||||||
{
|
|
||||||
asm ("flds (%0)" : : "r" (resp) : "st" );
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_DOUBLE)
|
|
||||||
{
|
|
||||||
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_LONGDOUBLE)
|
|
||||||
{
|
|
||||||
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
|
|
||||||
}
|
|
||||||
else if (rtype == FFI_TYPE_SINT64)
|
|
||||||
{
|
|
||||||
asm ("movl 0(%0),%%eax; movl 4(%0),%%edx"
|
|
||||||
: : "r"(resp)
|
|
||||||
: "eax", "edx");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_raw_closure (ffi_raw_closure* closure,
|
|
||||||
ffi_cif* cif,
|
|
||||||
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
FFI_ASSERT (cif->abi == FFI_SYSV);
|
|
||||||
|
|
||||||
// we currently don't support certain kinds of arguments for raw
|
|
||||||
// closures. This should be implemented by a seperate assembly language
|
|
||||||
// routine, since it would require argument processing, something we
|
|
||||||
// don't do now for performance.
|
|
||||||
|
|
||||||
for (i = cif->nargs-1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
|
|
||||||
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
|
|
||||||
(void*)closure);
|
|
||||||
|
|
||||||
closure->cif = cif;
|
|
||||||
closure->user_data = user_data;
|
|
||||||
closure->fun = fun;
|
|
||||||
|
|
||||||
return FFI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_prep_args_raw(char *stack, extended_cif *ecif)
|
|
||||||
{
|
|
||||||
memcpy (stack, ecif->avalue, ecif->cif->bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we borrow this routine from libffi (it must be changed, though, to
|
|
||||||
* actually call the function passed in the first argument. as of
|
|
||||||
* libffi-1.20, this is not the case.)
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern void
|
|
||||||
ffi_call_SYSV(void (*)(char *, extended_cif *),
|
|
||||||
/*@out@*/ extended_cif *,
|
|
||||||
unsigned, unsigned,
|
|
||||||
/*@out@*/ unsigned *,
|
|
||||||
void (*fn)());
|
|
||||||
|
|
||||||
void
|
|
||||||
ffi_raw_call(/*@dependent@*/ ffi_cif *cif,
|
|
||||||
void (*fn)(),
|
|
||||||
/*@out@*/ void *rvalue,
|
|
||||||
/*@dependent@*/ ffi_raw *fake_avalue)
|
|
||||||
{
|
|
||||||
extended_cif ecif;
|
|
||||||
void **avalue = (void **)fake_avalue;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
if ((rvalue == NULL) &&
|
|
||||||
(cif->rtype->type == FFI_TYPE_STRUCT))
|
|
||||||
{
|
|
||||||
/*@-sysunrecog@*/
|
|
||||||
ecif.rvalue = alloca(cif->rtype->size);
|
|
||||||
/*@=sysunrecog@*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ecif.rvalue = rvalue;
|
|
||||||
|
|
||||||
|
|
||||||
switch (cif->abi)
|
|
||||||
{
|
|
||||||
case FFI_SYSV:
|
|
||||||
/*@-usedef@*/
|
|
||||||
ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
/*@=usedef@*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
FFI_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
sysv.S - Copyright (c) 1996, 1998 Cygnus Solutions
|
|
||||||
|
|
||||||
X86 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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
.globl ffi_prep_args
|
|
||||||
|
|
||||||
# This assumes we are using gas.
|
|
||||||
.balign 16
|
|
||||||
.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
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
# Remove the space we pushed for the args
|
|
||||||
movl 16(%ebp),%ecx
|
|
||||||
addl %ecx,%esp
|
|
||||||
|
|
||||||
# Load %ecx with the return type code
|
|
||||||
movl 20(%ebp),%ecx
|
|
||||||
|
|
||||||
# If the return value pointer is NULL, assume no return value.
|
|
||||||
cmpl $0,24(%ebp)
|
|
||||||
jne retint
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
retint:
|
|
||||||
cmpl $FFI_TYPE_INT,%ecx
|
|
||||||
jne retfloat
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retfloat:
|
|
||||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
|
||||||
jne retdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstps (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retdouble:
|
|
||||||
cmpl $FFI_TYPE_DOUBLE,%ecx
|
|
||||||
jne retlongdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpl (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retlongdouble:
|
|
||||||
cmpl $FFI_TYPE_LONGDOUBLE,%ecx
|
|
||||||
jne retint64
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpt (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retint64:
|
|
||||||
cmpl $FFI_TYPE_SINT64,%ecx
|
|
||||||
jne retstruct
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
movl %edx,4(%ecx)
|
|
||||||
|
|
||||||
retstruct:
|
|
||||||
# Nothing to do!
|
|
||||||
|
|
||||||
noretval:
|
|
||||||
epilogue:
|
|
||||||
movl %ebp,%esp
|
|
||||||
popl %ebp
|
|
||||||
ret
|
|
||||||
.LFE1:
|
|
||||||
.ffi_call_SYSV_end:
|
|
||||||
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
|
|
||||||
|
|
||||||
.section .eh_frame,"aw",@progbits
|
|
||||||
__FRAME_BEGIN__:
|
|
||||||
.4byte .LLCIE1
|
|
||||||
.LSCIE1:
|
|
||||||
.4byte 0x0
|
|
||||||
.byte 0x1
|
|
||||||
.byte 0x0
|
|
||||||
.byte 0x1
|
|
||||||
.byte 0x7c
|
|
||||||
.byte 0x8
|
|
||||||
.byte 0xc
|
|
||||||
.byte 0x4
|
|
||||||
.byte 0x4
|
|
||||||
.byte 0x88
|
|
||||||
.byte 0x1
|
|
||||||
.align 4
|
|
||||||
.LECIE1:
|
|
||||||
.set .LLCIE1,.LECIE1-.LSCIE1
|
|
||||||
.4byte .LLFDE1
|
|
||||||
.LSFDE1:
|
|
||||||
.4byte .LSFDE1-__FRAME_BEGIN__
|
|
||||||
.4byte .LFB1
|
|
||||||
.4byte .LFE1-.LFB1
|
|
||||||
.byte 0x4
|
|
||||||
.4byte .LCFI0-.LFB1
|
|
||||||
.byte 0xe
|
|
||||||
.byte 0x8
|
|
||||||
.byte 0x85
|
|
||||||
.byte 0x2
|
|
||||||
.byte 0x4
|
|
||||||
.4byte .LCFI1-.LCFI0
|
|
||||||
.byte 0xd
|
|
||||||
.byte 0x5
|
|
||||||
.align 4
|
|
||||||
.LEFDE1:
|
|
||||||
.set .LLFDE1,.LEFDE1-.LSFDE1
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
/* -----------------------------------------------------------------------
|
|
||||||
win32.S - Copyright (c) 1996, 1998, 2001 Cygnus Solutions
|
|
||||||
|
|
||||||
X86 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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
.globl ffi_prep_args
|
|
||||||
|
|
||||||
# This assumes we are using gas.
|
|
||||||
.balign 16
|
|
||||||
.globl _ffi_call_SYSV
|
|
||||||
|
|
||||||
_ffi_call_SYSV:
|
|
||||||
pushl %ebp
|
|
||||||
movl %esp,%ebp
|
|
||||||
|
|
||||||
# Make room for all of the new args.
|
|
||||||
movl 16(%ebp),%ecx
|
|
||||||
subl %ecx,%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)
|
|
||||||
|
|
||||||
# Remove the space we pushed for the args
|
|
||||||
movl 16(%ebp),%ecx
|
|
||||||
addl %ecx,%esp
|
|
||||||
|
|
||||||
# Load %ecx with the return type code
|
|
||||||
movl 20(%ebp),%ecx
|
|
||||||
|
|
||||||
# If the return value pointer is NULL, assume no return value.
|
|
||||||
cmpl $0,24(%ebp)
|
|
||||||
jne retint
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
retint:
|
|
||||||
cmpl $FFI_TYPE_INT,%ecx
|
|
||||||
jne retfloat
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retfloat:
|
|
||||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
|
||||||
jne retdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstps (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retdouble:
|
|
||||||
cmpl $FFI_TYPE_DOUBLE,%ecx
|
|
||||||
jne retlongdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpl (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retlongdouble:
|
|
||||||
cmpl $FFI_TYPE_LONGDOUBLE,%ecx
|
|
||||||
jne retint64
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpt (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retint64:
|
|
||||||
cmpl $FFI_TYPE_SINT64,%ecx
|
|
||||||
jne retstruct
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
movl %edx,4(%ecx)
|
|
||||||
|
|
||||||
retstruct:
|
|
||||||
# Nothing to do!
|
|
||||||
|
|
||||||
noretval:
|
|
||||||
epilogue:
|
|
||||||
movl %ebp,%esp
|
|
||||||
popl %ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
.ffi_call_SYSV_end:
|
|
||||||
Reference in New Issue
Block a user