Import of v1 code.
This commit is contained in:
100
libffi/src/Makefile.am
Normal file
100
libffi/src/Makefile.am
Normal 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
409
libffi/src/Makefile.in
Normal 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
199
libffi/src/alpha/ffi.c
Normal 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
118
libffi/src/alpha/osf.S
Normal 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
185
libffi/src/arm/ffi.c
Normal 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
119
libffi/src/arm/sysv.S
Normal 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
67
libffi/src/debug.c
Normal 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
701
libffi/src/ffitest.c
Normal 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] = ≪
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
&ffi_type_sint64, args) == FFI_OK);
|
||||
|
||||
for (ll = 0LL; ll < 100LL; ll++)
|
||||
{
|
||||
ul++;
|
||||
ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
|
||||
CHECK(rlonglong == ll);
|
||||
}
|
||||
|
||||
for (ll = 55555555555000LL; ll < 55555555555100LL; ll++)
|
||||
{
|
||||
ul++;
|
||||
ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
|
||||
CHECK(rlonglong == ll);
|
||||
}
|
||||
#endif
|
||||
|
||||
args[0] = &ffi_type_schar;
|
||||
values[0] = ≻
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
&ffi_type_schar, args) == FFI_OK);
|
||||
|
||||
for (sc = (signed char) -127;
|
||||
sc < (signed char) 127; /*@-type@*/ sc++ /*@=type@*/)
|
||||
{
|
||||
ul++;
|
||||
ffi_call(&cif, FFI_FN(return_sc), &rint, values);
|
||||
CHECK(rint == (int) sc);
|
||||
}
|
||||
|
||||
args[0] = &ffi_type_uchar;
|
||||
values[0] = &uc;
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
&ffi_type_uchar, args) == FFI_OK);
|
||||
|
||||
for (uc = (unsigned char) '\x00';
|
||||
uc < (unsigned char) '\xff'; /*@-type@*/ uc++ /*@=type@*/)
|
||||
{
|
||||
ul++;
|
||||
ffi_call(&cif, FFI_FN(return_uc), &rint, values);
|
||||
CHECK(rint == (signed int) uc);
|
||||
}
|
||||
|
||||
printf("%lu return value tests run\n", ul);
|
||||
}
|
||||
|
||||
#ifdef BROKEN_LONG_DOUBLE
|
||||
printf ("This architecture has broken `long double' support. No floating point\ntests have been run.\n");
|
||||
#else
|
||||
/* float arg tests */
|
||||
{
|
||||
args[0] = &ffi_type_float;
|
||||
values[0] = &f;
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
&ffi_type_longdouble, args) == FFI_OK);
|
||||
|
||||
f = 3.14159;
|
||||
|
||||
#if 0
|
||||
/* This is ifdef'd out for now. long double support under SunOS/gcc
|
||||
is pretty much non-existent. You'll get the odd bus error in library
|
||||
routines like printf(). */
|
||||
printf ("%Lf\n", ldblit(f));
|
||||
#endif
|
||||
ld = 666;
|
||||
ffi_call(&cif, FFI_FN(ldblit), &ld, values);
|
||||
|
||||
#if 0
|
||||
/* This is ifdef'd out for now. long double support under SunOS/gcc
|
||||
is pretty much non-existent. You'll get the odd bus error in library
|
||||
routines like printf(). */
|
||||
printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON);
|
||||
#endif
|
||||
|
||||
/* These are not always the same!! Check for a reasonable delta */
|
||||
/*@-realcompare@*/
|
||||
if (ld - ldblit(f) < LDBL_EPSILON)
|
||||
/*@=realcompare@*/
|
||||
puts("long double return value tests ok!");
|
||||
else
|
||||
CHECK(0);
|
||||
}
|
||||
|
||||
/* float arg tests */
|
||||
{
|
||||
args[0] = &ffi_type_sint;
|
||||
values[0] = &si1;
|
||||
args[1] = &ffi_type_float;
|
||||
values[1] = &f;
|
||||
args[2] = &ffi_type_double;
|
||||
values[2] = &d;
|
||||
args[3] = &ffi_type_longdouble;
|
||||
values[3] = &ld;
|
||||
args[4] = &ffi_type_sint;
|
||||
values[4] = &si2;
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 5,
|
||||
&ffi_type_sint, args) == FFI_OK);
|
||||
|
||||
si1 = 6;
|
||||
f = 3.14159;
|
||||
d = (double)1.0/(double)3.0;
|
||||
ld = 2.71828182846L;
|
||||
si2 = 10;
|
||||
|
||||
floating (si1, f, d, ld, si2);
|
||||
|
||||
ffi_call(&cif, FFI_FN(floating), &rint, values);
|
||||
|
||||
printf ("%d vs %d\n", rint, floating (si1, f, d, ld, si2));
|
||||
|
||||
CHECK(rint == floating(si1, f, d, ld, si2));
|
||||
|
||||
printf("float arg tests ok!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* strlen tests */
|
||||
{
|
||||
args[0] = &ffi_type_pointer;
|
||||
values[0] = (void*) &s;
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
&ffi_type_sint, args) == FFI_OK);
|
||||
|
||||
s = "a";
|
||||
ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
|
||||
CHECK(rint == 1);
|
||||
|
||||
s = "1234567";
|
||||
ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
|
||||
CHECK(rint == 7);
|
||||
|
||||
s = "1234567890123456789012345";
|
||||
ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
|
||||
CHECK(rint == 25);
|
||||
|
||||
printf("strlen tests passed\n");
|
||||
}
|
||||
|
||||
/* float arg tests */
|
||||
{
|
||||
args[0] = &ffi_type_float;
|
||||
values[0] = &f;
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
&ffi_type_double, args) == FFI_OK);
|
||||
|
||||
f = 3.14159;
|
||||
|
||||
ffi_call(&cif, FFI_FN(dblit), &d, values);
|
||||
|
||||
/* These are not always the same!! Check for a reasonable delta */
|
||||
/*@-realcompare@*/
|
||||
CHECK(d - dblit(f) < DBL_EPSILON);
|
||||
/*@=realcompare@*/
|
||||
|
||||
printf("double return value tests ok!\n");
|
||||
}
|
||||
|
||||
/* many arg tests */
|
||||
{
|
||||
float ff;
|
||||
float fa[13];
|
||||
|
||||
for (ul = 0; ul < 13; ul++)
|
||||
{
|
||||
args[ul] = &ffi_type_float;
|
||||
values[ul] = &fa[ul];
|
||||
fa[ul] = (float) ul;
|
||||
}
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13,
|
||||
&ffi_type_float, args) == FFI_OK);
|
||||
|
||||
/*@-usedef@*/
|
||||
ff = many(fa[0], fa[1],
|
||||
fa[2], fa[3],
|
||||
fa[4], fa[5],
|
||||
fa[6], fa[7],
|
||||
fa[8], fa[9],
|
||||
fa[10],fa[11],fa[12]);
|
||||
/*@=usedef@*/
|
||||
|
||||
ffi_call(&cif, FFI_FN(many), &f, values);
|
||||
|
||||
/*@-realcompare@*/
|
||||
if (f - ff < FLT_EPSILON)
|
||||
/*@=realcompare@*/
|
||||
printf("many arg tests ok!\n");
|
||||
else
|
||||
#ifdef POWERPC
|
||||
printf("many arg tests failed! This is a gcc bug.\n");
|
||||
#else
|
||||
CHECK(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* promotion tests */
|
||||
{
|
||||
args[0] = &ffi_type_schar;
|
||||
args[1] = &ffi_type_sshort;
|
||||
args[2] = &ffi_type_uchar;
|
||||
args[3] = &ffi_type_ushort;
|
||||
values[0] = ≻
|
||||
values[1] = &ss;
|
||||
values[2] = &uc;
|
||||
values[3] = &us;
|
||||
|
||||
/* Initialize the cif */
|
||||
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
|
||||
&ffi_type_sint, args) == FFI_OK);
|
||||
|
||||
us = 0;
|
||||
ul = 0;
|
||||
|
||||
for (sc = (signed char) -127;
|
||||
sc <= (signed char) 120; /*@-type@*/ sc += 1 /*@=type@*/)
|
||||
for (ss = -30000; ss <= 30000; ss += 10000)
|
||||
for (uc = (unsigned char) 0;
|
||||
uc <= (unsigned char) 200; /*@-type@*/ uc += 20 /*@=type@*/)
|
||||
for (us = 0; us <= 60000; us += 10000)
|
||||
{
|
||||
ul++;
|
||||
ffi_call(&cif, FFI_FN(promotion), &rint, values);
|
||||
CHECK(rint == (int) sc + (int) ss + (int) uc + (int) us);
|
||||
}
|
||||
printf("%lu promotion tests run\n", ul);
|
||||
}
|
||||
|
||||
/* 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
184
libffi/src/m68k/ffi.c
Normal 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
96
libffi/src/m68k/sysv.S
Normal 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
471
libffi/src/mips/ffi.c
Normal 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
320
libffi/src/mips/n32.S
Normal 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
14
libffi/src/mips/n32.s
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "n32.S"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
173
libffi/src/mips/o32.S
Normal file
173
libffi/src/mips/o32.S
Normal 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
2
libffi/src/mips/o32.s
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "o32.S"
|
||||
|
||||
128
libffi/src/powerpc/asm.h
Normal file
128
libffi/src/powerpc/asm.h
Normal 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
423
libffi/src/powerpc/ffi.c
Normal 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
119
libffi/src/powerpc/sysv.S
Normal 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
143
libffi/src/prep_cif.c
Normal 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
216
libffi/src/sparc/ffi.c
Normal 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
85
libffi/src/sparc/v8.S
Normal 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
98
libffi/src/types.c
Normal 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
192
libffi/src/x86/ffi.c
Normal 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
129
libffi/src/x86/sysv.S
Normal 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
|
||||
|
||||
Reference in New Issue
Block a user