Import of v1 code.

This commit is contained in:
green
1998-11-29 16:48:16 +00:00
commit bc75c54bd3
48 changed files with 16071 additions and 0 deletions

100
libffi/src/Makefile.am Normal file
View File

@@ -0,0 +1,100 @@
## 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
##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

409
libffi/src/Makefile.in Normal file
View File

@@ -0,0 +1,409 @@
# Makefile.in generated automatically by automake 1.2 from Makefile.am
# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
SHELL = /bin/sh
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
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@
transform = @program_transform_name@
NORMAL_INSTALL = true
PRE_INSTALL = true
POST_INSTALL = true
NORMAL_UNINSTALL = true
PRE_UNINSTALL = true
POST_UNINSTALL = true
host_alias = @host_alias@
host_triplet = @host@
CC = @CC@
LD = @LD@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAKEINFO = @MAKEINFO@
NM = @NM@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
SHELL = @SHELL@
TARGET = @TARGET@
TARGETDIR = @TARGETDIR@
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 = $(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC)
@MIPS_SGI_TRUE@libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_SGI)
@X86_TRUE@libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_X86)
@SPARC_TRUE@libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_SPARC)
@ALPHA_TRUE@libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_ALPHA)
@M68K_TRUE@libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_M68K)
@POWERPC_TRUE@libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC)
@ARM_TRUE@libffi_la_SOURCES = $(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
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 =
@SPARC_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
@SPARC_TRUE@v8.lo
@MIPS_SGI_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
@MIPS_SGI_TRUE@o32.lo n32.lo
@MIPS_GCC_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
@MIPS_GCC_TRUE@o32.lo n32.lo
@M68K_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
@M68K_TRUE@sysv.lo
@ALPHA_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
@ALPHA_TRUE@osf.lo
@X86_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
@X86_TRUE@sysv.lo
@ARM_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo sysv.lo \
@ARM_TRUE@ffi.lo
@POWERPC_TRUE@libffi_la_OBJECTS = debug.lo prep_cif.lo types.lo ffi.lo \
@POWERPC_TRUE@sysv.lo
PROGRAMS = $(noinst_PROGRAMS)
ffitest_OBJECTS = ffitest.o
ffitest_DEPENDENCIES = libffi.la
ffitest_LDFLAGS =
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
DIST_COMMON = ChangeLog Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP = --best
DEP_FILES = .deps/debug.P .deps/ffi.P .deps/ffitest.P .deps/n32.P \
.deps/o32.P .deps/osf.P .deps/prep_cif.P .deps/sysv.P .deps/types.P \
.deps/v8.P
SOURCES = $(libffi_la_SOURCES) $(ffitest_SOURCES)
OBJECTS = $(libffi_la_OBJECTS) $(ffitest_OBJECTS)
default: all
.SUFFIXES:
.SUFFIXES: .S .c .lo .o .s
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
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) $(libdir)
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
if test -f $$p; then \
echo "$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(libdir)/$$p"; \
$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(libdir)/$$p; \
else :; fi; \
done
uninstall-libLTLIBRARIES:
$(NORMAL_UNINSTALL)
list='$(lib_LTLIBRARIES)'; for p in $$list; do \
$(LIBTOOL) --mode=uninstall rm -f $(libdir)/$$p; \
done
.c.o:
$(COMPILE) -c $<
mostlyclean-compile:
rm -f *.o core
clean-compile:
distclean-compile:
rm -f *.tab.c
maintainer-clean-compile:
.c.lo:
$(LIBTOOL) --mode=compile $(COMPILE) -c $<
mostlyclean-libtool:
rm -f *.lo
clean-libtool:
rm -rf .libs
distclean-libtool:
maintainer-clean-libtool:
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: $(ffitest_OBJECTS) $(ffitest_DEPENDENCIES)
@rm -f ffitest
$(LINK) $(ffitest_LDFLAGS) $(ffitest_OBJECTS) $(ffitest_LDADD) $(LIBS)
tags: TAGS
ID: $(HEADERS) $(SOURCES)
here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
tags=; \
here=`pwd`; \
test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = src
distdir: $(DISTFILES)
here=`cd $(top_builddir) && pwd`; \
top_distdir=`cd $(top_distdir) && pwd`; \
cd $(top_srcdir) \
&& $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign src/Makefile
$(mkinstalldirs) $(distdir)/alpha $(distdir)/arm $(distdir)/m68k \
$(distdir)/mips $(distdir)/powerpc $(distdir)/sparc \
$(distdir)/x86
@for file in $(DISTFILES); do \
d=$(srcdir); \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done
MKDEP = gcc -M $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
-include .deps/.P
.deps/.P: $(BUILT_SOURCES)
echo > $@
-include $(DEP_FILES)
mostlyclean-depend:
clean-depend:
distclean-depend:
maintainer-clean-depend:
rm -rf .deps
.deps/%.P: %.c
@echo "Computing dependencies for $<..."
@o='o'; \
test -n "$o" && o='$$o'; \
$(MKDEP) $< >$@.tmp \
&& sed "s,^\(.*\)\.o:,\1.$$o \1.l$$o $@:," < $@.tmp > $@ \
&& rm -f $@.tmp
info:
dvi:
check: all
$(MAKE)
installcheck:
install-exec: install-libLTLIBRARIES
@$(NORMAL_INSTALL)
install-data:
@$(NORMAL_INSTALL)
install: install-exec install-data all
@:
uninstall: uninstall-libLTLIBRARIES
all: Makefile $(LTLIBRARIES) $(PROGRAMS)
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
installdirs:
$(mkinstalldirs) $(libdir)
mostlyclean-generic:
test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
rm -f Makefile $(DISTCLEANFILES)
rm -f config.cache config.log stamp-h stamp-h[0-9]*
test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
mostlyclean: mostlyclean-libLTLIBRARIES mostlyclean-compile \
mostlyclean-libtool mostlyclean-noinstPROGRAMS \
mostlyclean-tags mostlyclean-depend mostlyclean-generic
clean: clean-libLTLIBRARIES clean-compile clean-libtool \
clean-noinstPROGRAMS clean-tags clean-depend \
clean-generic mostlyclean
distclean: distclean-libLTLIBRARIES distclean-compile distclean-libtool \
distclean-noinstPROGRAMS distclean-tags \
distclean-depend distclean-generic clean
rm -f config.status
rm -f libtool
maintainer-clean: maintainer-clean-libLTLIBRARIES \
maintainer-clean-compile maintainer-clean-libtool \
maintainer-clean-noinstPROGRAMS maintainer-clean-tags \
maintainer-clean-depend maintainer-clean-generic \
distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
.PHONY: default 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 mostlyclean-depend \
distclean-depend clean-depend maintainer-clean-depend info dvi \
installcheck install-exec install-data install uninstall all \
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:

199
libffi/src/alpha/ffi.c Normal file
View File

@@ -0,0 +1,199 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Cygnus Solutions
Alpha Foreign Function Interface
$Id: ffi.c,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 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 */
static void
ffi_prep_args(char *stack, extended_cif *ecif, int bytes, int flags)
{
register long i, avn;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
/* To streamline things in the assembly code, we always allocate 12
words for loading up the int and fp argument registers. The layout
is as when processing varargs: the 6 fp args, the 6 int args, then
the incoming stack. ARGP points to the first int slot. */
argp = stack + 6 * SIZEOF_ARG;
memset (stack, 0, 12 * SIZEOF_ARG);
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
{
*(void **) argp = ecif->rvalue;
argp += sizeof(void *);
}
i = 0;
avn = ecif->cif->nargs;
p_arg = ecif->cif->arg_types;
p_argv = ecif->avalue;
while (i < avn)
{
size_t z = ALIGN((*p_arg)->size, SIZEOF_ARG);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(SINT64 *) argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(UINT64 *) argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(SINT64 *) argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(UINT64 *) argp = *(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(SINT64 *) argp = *(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(UINT64 *) argp = *(UINT32 *)(* p_argv);
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
*(UINT64 *) argp = *(UINT64 *)(* p_argv);
break;
case FFI_TYPE_FLOAT:
if (argp - stack < 12 * SIZEOF_ARG)
{
/* Note the conversion -- all the fp regs are loaded as
doubles. The in-register format is the same. */
*(double *) (argp - 6 * SIZEOF_ARG) = *(float *)(* p_argv);
}
else
*(float *) argp = *(float *)(* p_argv);
break;
case FFI_TYPE_DOUBLE:
if (argp - stack < 12 * SIZEOF_ARG)
*(double *) (argp - 6 * SIZEOF_ARG) = *(double *)(* p_argv);
else
*(double *) argp = *(double *)(* p_argv);
break;
case FFI_TYPE_STRUCT:
memcpy(argp, *p_argv, (*p_arg)->size);
break;
default:
FFI_ASSERT(0);
}
argp += z;
i++, p_arg++, p_argv++;
}
}
/* Perform machine dependent cif processing */
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Adjust cif->bytes. to include 12 words for the temporary register
argument loading area. This will be removed before the call. */
cif->bytes += 6*SIZEOF_ARG;
if (cif->bytes < 12*SIZEOF_ARG)
cif->bytes = 12*SIZEOF_ARG;
/* The stack must be double word aligned, so round bytes up
appropriately. */
cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
cif->flags = cif->rtype->type;
break;
case FFI_TYPE_FLOAT:
cif->flags = FFI_TYPE_FLOAT;
break;
case FFI_TYPE_DOUBLE:
cif->flags = FFI_TYPE_DOUBLE;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
extern int ffi_call_osf(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)
{
case FFI_OSF:
ffi_call_osf(ffi_prep_args, &ecif, cif->bytes,
cif->flags, rvalue, fn);
break;
default:
FFI_ASSERT(0);
break;
}
}

118
libffi/src/alpha/osf.S Normal file
View File

@@ -0,0 +1,118 @@
/* -----------------------------------------------------------------------
osf.S - Copyright (c) 1998 Cygnus Solutions
Alpha/OSF Foreign Function Interface
$Id: osf.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 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 callback $16
#define ecifp $17
#define bytes $18
#define flags $19
#define raddr $20
#define fn $21
#define flags_ofs 16
#define raddr_ofs 24
#define fn_ofs 32
#define SIZEOF_FRAME (6*8)
.text
.align 4
.globl ffi_call_osf
.ent ffi_call_osf
ffi_call_osf:
lda $30, -SIZEOF_FRAME($30)
stq $26, 0($30)
stq $15, 8($30)
stq flags, flags_ofs($30)
stq raddr, raddr_ofs($30)
stq fn, fn_ofs($30)
mov $30, $15
.frame $15, SIZEOF_FRAME, $26, 0
.mask 0x4008000, -SIZEOF_FRAME
.prologue 0
mov callback, $27 # mov callback into place
subq $30, bytes, $30 # allocate stack space
# Call ffi_prep_args; ecif, bytes and flags are already in place.
mov $30, $16 # push stack arg
jsr $26, ($27), 0
# Load up all of the (potential) argument registers.
ldt $f16, 0($30)
ldt $f17, 8($30)
ldt $f18, 16($30)
ldt $f19, 24($30)
ldt $f20, 32($30)
ldt $f21, 40($30)
ldq $16, 48($30)
ldq $17, 56($30)
ldq $18, 64($30)
ldq $19, 72($30)
ldq $20, 80($30)
ldq $21, 88($30)
# Get rid of the arg reg temp space and call the function.
ldq $27, fn_ofs($15)
lda $30, 12*8($30)
jsr $26, ($27), 0
# If the return value pointer is NULL, assume no return value.
ldq raddr, raddr_ofs($15)
beq raddr, $noretval
ldq flags, flags_ofs($15)
cmpeq flags, FFI_TYPE_INT, $1
bne $1, $retint
cmpeq flags, FFI_TYPE_FLOAT, $2
bne $2, $retfloat
cmpeq flags, FFI_TYPE_DOUBLE, $3
bne $3, $retdouble
br $retstruct
.align 3
$retint:
stq $0, 0(raddr)
br $noretval
$retfloat:
sts $f0, 0(raddr)
br $noretval
$retdouble:
stt $f0, 0(raddr)
$retstruct:
$noretval:
mov $15, $30
ldq $26, 0($15)
ldq $15, 8($15)
lda $30, SIZEOF_FRAME($30)
ret
.end ffi_call_osf

185
libffi/src/arm/ffi.c Normal file
View File

@@ -0,0 +1,185 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Cygnus Solutions
ARM Foreign Function Interface
$Id: ffi.c,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 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;
}
}

119
libffi/src/arm/sysv.S Normal file
View File

@@ -0,0 +1,119 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1998 Cygnus Solutions
ARM Foreign Function Interface
$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 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
bne retdouble
stfs f0, [a3]
b epilogue
# return DOUBLE or LONGDOUBLE
retdouble:
cmp a4, #FFI_TYPE_DOUBLE
bne epilogue
stfs f0, [a3, #0]
stfs f1, [a3, #4]
b epilogue
epilogue:
ldmfd sp!, {a1-a4, fp, pc}
.ffi_call_SYSV_end:
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)

67
libffi/src/debug.c Normal file
View File

@@ -0,0 +1,67 @@
/* -----------------------------------------------------------------------
debug.c - Copyright (c) 1996 Cygnus Solutions
$Id: debug.c,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 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 <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);
}

701
libffi/src/ffitest.c Normal file
View File

@@ -0,0 +1,701 @@
/* -----------------------------------------------------------------------
ffitest.c - Copyright (c) 1996, 1997, 1998 Cygnus Solutions
$Id: ffitest.c,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 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 <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;
}
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(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(SPARC) /* || defined(ARM) */
puts ("long long tests not run. This is a known bug on this architecture.");
#else
args[0] = &ffi_type_sint64;
values[0] = &ll;
/* 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] = &sc;
/* 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] = &sc;
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);
}
/* 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);
}
/* If we arrived here, all is good */
(void) puts("\nLooks good. No surprises.\n");
/*@-compdestroy@*/
return 0;
}

184
libffi/src/m68k/ffi.c Normal file
View File

@@ -0,0 +1,184 @@
/* -----------------------------------------------------------------------
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;
}
}

96
libffi/src/m68k/sysv.S Normal file
View File

@@ -0,0 +1,96 @@
/* -----------------------------------------------------------------------
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

471
libffi/src/mips/ffi.c Normal file
View File

@@ -0,0 +1,471 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996 Cygnus Solutions
MIPS Foreign Function Interface
$Id: ffi.c,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 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;
}
}

320
libffi/src/mips/n32.S Normal file
View File

@@ -0,0 +1,320 @@
/* -----------------------------------------------------------------------
n32.S - Copyright (c) 1996, 1998 Cygnus Solutions
MIPS Foreign Function Interface
$Id: n32.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 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

14
libffi/src/mips/n32.s Normal file
View File

@@ -0,0 +1,14 @@
#include "n32.S"

173
libffi/src/mips/o32.S Normal file
View File

@@ -0,0 +1,173 @@
/* -----------------------------------------------------------------------
o32.S - Copyright (c) 1996, 1998 Cygnus Solutions
MIPS Foreign Function Interface
$Id: o32.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 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

2
libffi/src/mips/o32.s Normal file
View File

@@ -0,0 +1,2 @@
#include "o32.S"

128
libffi/src/powerpc/asm.h Normal file
View File

@@ -0,0 +1,128 @@
/* -----------------------------------------------------------------------
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

423
libffi/src/powerpc/ffi.c Normal file
View File

@@ -0,0 +1,423 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Geoffrey Keating
PowerPC Foreign Function Interface
$Id: ffi.c,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.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
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
{
*(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;
}
}

119
libffi/src/powerpc/sysv.S Normal file
View File

@@ -0,0 +1,119 @@
/* -----------------------------------------------------------------------
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)

143
libffi/src/prep_cif.c Normal file
View File

@@ -0,0 +1,143 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 1996, 1998 Cygnus Solutions
$Id: prep_cif.c,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 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>
/* 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)
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)->type == FFI_TYPE_LONGDOUBLE)
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);
}

216
libffi/src/sparc/ffi.c Normal file
View File

@@ -0,0 +1,216 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996 Cygnus Solutions
Sparc Foreign Function Interface
$Id: ffi.c,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 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(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(void*);
/* 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 ) */
*(void **) argp = ecif->rvalue;
/* And 1 word for the structure return value. */
argp += sizeof(void*);
#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
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE)
{
*(unsigned int *) argp = (unsigned int)(* p_argv);
z = sizeof(void*);
}
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;
case FFI_TYPE_SINT32:
*(signed int *) argp = *(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(unsigned int *) argp = *(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)
{
/* 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 += sizeof(void*);
/* 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;
/* Adjust cif->bytes. to include 16 words for the window save area,
and maybe the struct/union return pointer area, */
cif->bytes += 64;
/* The stack must be double word aligned, so round bytes up
appropriately. */
cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
cif->flags = cif->rtype->type;
break;
case FFI_TYPE_FLOAT:
cif->flags = FFI_TYPE_FLOAT;
break;
case FFI_TYPE_DOUBLE:
cif->flags = FFI_TYPE_DOUBLE;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
extern int ffi_call_V8(void *, extended_cif *, unsigned,
unsigned, unsigned *, 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))
ecif.rvalue = alloca(cif->rtype->size);
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
case FFI_V8:
ffi_call_V8(ffi_prep_args, &ecif, cif->bytes,
cif->flags, rvalue, fn);
break;
default:
FFI_ASSERT(0);
break;
}
}

85
libffi/src/sparc/v8.S Normal file
View File

@@ -0,0 +1,85 @@
/* -----------------------------------------------------------------------
v8.S - Copyright (c) 1996, 1997 Cygnus Solutions
Sparc Foreign Function Interface
$Id: v8.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 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
! 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_DOUBLE
bne done
nop
st %f0, [%i4+0]
st %f1, [%i4+4]
done:
ret
restore
.ffi_call_V8_end:
.size ffi_call_V8,.ffi_call_V8_end-ffi_call_V8

98
libffi/src/types.c Normal file
View File

@@ -0,0 +1,98 @@
/* -----------------------------------------------------------------------
types.c - Copyright (c) 1996, 1998 Cygnus Solutions
Predefined ffi_types needed by libffi.
$Id: types.c,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 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>
/* 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(pointer, 4, 4, FFI_TYPE_POINTER);
FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
#ifdef X86
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 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);
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
#else
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE);
#endif

192
libffi/src/x86/ffi.c Normal file
View File

@@ -0,0 +1,192 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 1998 Cygnus Solutions
x86 Foreign Function Interface
$Id: ffi.c,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 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_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
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;
}
}

129
libffi/src/x86/sysv.S Normal file
View File

@@ -0,0 +1,129 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1996, 1998 Cygnus Solutions
X86 Foreign Function Interface
$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 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:
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 ffi_prep_args
# 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:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV