libffi: Sync with libffi 3.4.2
Merged commit: f9ea41683444ebe11cfa45b05223899764df28fb
This commit is contained in:
parent
d738405e7f
commit
92456a4e56
236 changed files with 17049 additions and 30145 deletions
4
libffi/.gitattributes
vendored
Normal file
4
libffi/.gitattributes
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
* text=auto
|
||||
|
||||
*.sln text eol=crlf
|
||||
*.vcxproj* text eol=crlf
|
|
@ -1,4 +1,4 @@
|
|||
libffi - Copyright (c) 1996-2014 Anthony Green, Red Hat, Inc and others.
|
||||
libffi - Copyright (c) 1996-2021 Anthony Green, Red Hat, Inc and others.
|
||||
See source files for details.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
|
353
libffi/LICENSE-BUILDTOOLS
Normal file
353
libffi/LICENSE-BUILDTOOLS
Normal file
|
@ -0,0 +1,353 @@
|
|||
The libffi source distribution contains certain code that is not part
|
||||
of libffi, and is only used as tooling to assist with the building and
|
||||
testing of libffi. This includes the msvcc.sh script used to wrap the
|
||||
Microsoft compiler with GNU compatible command-line options,
|
||||
make_sunver.pl, and the libffi test code distributed in the
|
||||
testsuite/libffi.bhaible directory. This code is distributed with
|
||||
libffi for the purpose of convenience only, and libffi is in no way
|
||||
derived from this code.
|
||||
|
||||
msvcc.sh an testsuite/libffi.bhaible are both distributed under the
|
||||
terms of the GNU GPL version 2, as below.
|
||||
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
4
libffi/MERGE
Normal file
4
libffi/MERGE
Normal file
|
@ -0,0 +1,4 @@
|
|||
f9ea41683444ebe11cfa45b05223899764df28fb
|
||||
|
||||
The first line of this file holds the git revision number of the
|
||||
last merge done from the master library sources.
|
|
@ -1,107 +1,31 @@
|
|||
## Process this with automake to create Makefile.in
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign subdir-objects info-in-builddir
|
||||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||
|
||||
ACLOCAL_AMFLAGS = -I .. -I ../config
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = include testsuite man
|
||||
if BUILD_DOCS
|
||||
## This hack is needed because it doesn't seem possible to make a
|
||||
## conditional info_TEXINFOS in Automake. At least Automake 1.14
|
||||
## either gives errors -- if this attempted in the most
|
||||
## straightforward way -- or simply unconditionally tries to build the
|
||||
## info file.
|
||||
SUBDIRS += doc
|
||||
endif
|
||||
|
||||
EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \
|
||||
ChangeLog.libffi ChangeLog.libffi-3.1 \
|
||||
EXTRA_DIST = LICENSE ChangeLog.old \
|
||||
m4/libtool.m4 m4/lt~obsolete.m4 \
|
||||
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \
|
||||
m4/ltversion.m4 src/debug.c msvcc.sh \
|
||||
generate-darwin-source-and-headers.py \
|
||||
libffi.xcodeproj/project.pbxproj \
|
||||
libtool-ldflags
|
||||
libtool-ldflags libtool-version configure.host README.md \
|
||||
libffi.map.in LICENSE-BUILDTOOLS msvc_build make_sunver.pl
|
||||
|
||||
# local.exp is generated by configure
|
||||
DISTCLEANFILES = local.exp
|
||||
|
||||
# Automake Documentation:
|
||||
# If your package has Texinfo files in many directories, you can use the
|
||||
# variable TEXINFO_TEX to tell Automake where to find the canonical
|
||||
# `texinfo.tex' for your package. The value of this variable should be
|
||||
# the relative path from the current `Makefile.am' to `texinfo.tex'.
|
||||
TEXINFO_TEX = ../gcc/doc/include/texinfo.tex
|
||||
|
||||
# Defines info, dvi, pdf and html targets
|
||||
MAKEINFOFLAGS = -I $(srcdir)/../gcc/doc/include
|
||||
info_TEXINFOS = doc/libffi.texi
|
||||
|
||||
# AM_CONDITIONAL on configure option --generated-files-in-srcdir
|
||||
if GENINSRC
|
||||
STAMP_GENINSRC = stamp-geninsrc
|
||||
else
|
||||
STAMP_GENINSRC =
|
||||
endif
|
||||
|
||||
# AM_CONDITIONAL on configure check ACX_CHECK_PROG_VER([MAKEINFO])
|
||||
if BUILD_INFO
|
||||
STAMP_BUILD_INFO = stamp-build-info
|
||||
else
|
||||
STAMP_BUILD_INFO =
|
||||
endif
|
||||
|
||||
all-local: $(STAMP_GENINSRC)
|
||||
|
||||
stamp-geninsrc: doc/libffi.info
|
||||
cp -p $(top_builddir)/doc/libffi.info $(srcdir)/doc/libffi.info
|
||||
@touch $@
|
||||
|
||||
doc/libffi.info: $(STAMP_BUILD_INFO)
|
||||
|
||||
stamp-build-info: doc/libffi.texi $(srcdir)/doc/version.texi doc/$(am__dirstamp)
|
||||
$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)/doc -o doc/libffi.info $(srcdir)/doc/libffi.texi
|
||||
@touch $@
|
||||
|
||||
CLEANFILES = $(STAMP_GENINSRC) $(STAMP_BUILD_INFO)
|
||||
MAINTAINERCLEANFILES = $(srcdir)/doc/libffi.info
|
||||
|
||||
## ################################################################
|
||||
|
||||
##
|
||||
## This section is for make and multilib madness.
|
||||
##
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"mandir=$(mandir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"NM=$(NM)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
# Subdir rules rely on $(FLAGS_TO_PASS)
|
||||
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
|
||||
|
||||
|
@ -114,82 +38,62 @@ toolexeclib_LTLIBRARIES = libffi.la
|
|||
noinst_LTLIBRARIES = libffi_convenience.la
|
||||
|
||||
libffi_la_SOURCES = src/prep_cif.c src/types.c \
|
||||
src/raw_api.c src/java_raw_api.c src/closures.c
|
||||
src/raw_api.c src/java_raw_api.c src/closures.c \
|
||||
src/tramp.c
|
||||
|
||||
if FFI_DEBUG
|
||||
libffi_la_SOURCES += src/debug.c
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
src/aarch64/ffitarget.h src/aarch64/internal.h \
|
||||
noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h \
|
||||
src/alpha/ffitarget.h src/alpha/internal.h \
|
||||
src/arc/ffitarget.h \
|
||||
src/arm/ffitarget.h src/arm/internal.h \
|
||||
src/avr32/ffitarget.h \
|
||||
src/bfin/ffitarget.h \
|
||||
src/cris/ffitarget.h \
|
||||
src/frv/ffitarget.h \
|
||||
src/arc/ffitarget.h src/arm/ffitarget.h src/arm/internal.h \
|
||||
src/avr32/ffitarget.h src/bfin/ffitarget.h \
|
||||
src/cris/ffitarget.h src/csky/ffitarget.h src/frv/ffitarget.h \
|
||||
src/ia64/ffitarget.h src/ia64/ia64_flags.h \
|
||||
src/m32r/ffitarget.h \
|
||||
src/m68k/ffitarget.h \
|
||||
src/m88k/ffitarget.h \
|
||||
src/metag/ffitarget.h \
|
||||
src/microblaze/ffitarget.h \
|
||||
src/mips/ffitarget.h \
|
||||
src/moxie/ffitarget.h \
|
||||
src/nios2/ffitarget.h \
|
||||
src/or1k/ffitarget.h \
|
||||
src/pa/ffitarget.h \
|
||||
src/powerpc/ffitarget.h src/powerpc/asm.h src/powerpc/ffi_powerpc.h \
|
||||
src/riscv/ffitarget.h \
|
||||
src/s390/ffitarget.h \
|
||||
src/sh/ffitarget.h \
|
||||
src/sh64/ffitarget.h \
|
||||
src/sparc/ffitarget.h src/sparc/internal.h \
|
||||
src/tile/ffitarget.h \
|
||||
src/vax/ffitarget.h \
|
||||
src/m32r/ffitarget.h src/m68k/ffitarget.h \
|
||||
src/m88k/ffitarget.h src/metag/ffitarget.h \
|
||||
src/microblaze/ffitarget.h src/mips/ffitarget.h \
|
||||
src/moxie/ffitarget.h src/nios2/ffitarget.h \
|
||||
src/or1k/ffitarget.h src/pa/ffitarget.h \
|
||||
src/powerpc/ffitarget.h src/powerpc/asm.h \
|
||||
src/powerpc/ffi_powerpc.h src/riscv/ffitarget.h \
|
||||
src/s390/ffitarget.h src/s390/internal.h src/sh/ffitarget.h \
|
||||
src/sh64/ffitarget.h src/sparc/ffitarget.h \
|
||||
src/sparc/internal.h src/tile/ffitarget.h src/vax/ffitarget.h \
|
||||
src/x86/ffitarget.h src/x86/internal.h src/x86/internal64.h \
|
||||
src/xtensa/ffitarget.h \
|
||||
src/dlmalloc.c
|
||||
src/x86/asmnames.h src/xtensa/ffitarget.h src/dlmalloc.c \
|
||||
src/kvx/ffitarget.h
|
||||
|
||||
EXTRA_libffi_la_SOURCES = \
|
||||
src/aarch64/ffi.c src/aarch64/sysv.S \
|
||||
src/alpha/ffi.c src/alpha/osf.S \
|
||||
src/arc/ffi.c src/arc/arcompact.S \
|
||||
src/arm/ffi.c src/arm/sysv.S \
|
||||
src/avr32/ffi.c src/avr32/sysv.S \
|
||||
src/bfin/ffi.c src/bfin/sysv.S \
|
||||
src/cris/ffi.c src/cris/sysv.S \
|
||||
src/frv/ffi.c src/frv/eabi.S \
|
||||
src/ia64/ffi.c src/ia64/unix.S \
|
||||
src/m32r/ffi.c src/m32r/sysv.S \
|
||||
src/m68k/ffi.c src/m68k/sysv.S \
|
||||
src/m88k/ffi.c src/m88k/obsd.S \
|
||||
src/metag/ffi.c src/metag/sysv.S \
|
||||
src/microblaze/ffi.c src/microblaze/sysv.S \
|
||||
src/mips/ffi.c src/mips/o32.S src/mips/n32.S \
|
||||
src/moxie/ffi.c src/moxie/eabi.S \
|
||||
src/nios2/ffi.c src/nios2/sysv.S \
|
||||
src/or1k/ffi.c src/or1k/sysv.S \
|
||||
src/pa/ffi.c src/pa/linux.S src/pa/hpux32.S \
|
||||
src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \
|
||||
src/powerpc/sysv.S src/powerpc/linux64.S \
|
||||
src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S \
|
||||
src/powerpc/aix.S src/powerpc/darwin.S src/powerpc/aix_closure.S \
|
||||
src/powerpc/darwin_closure.S src/powerpc/ffi_darwin.c \
|
||||
src/riscv/ffi.c src/riscv/sysv.S \
|
||||
src/s390/ffi.c src/s390/sysv.S \
|
||||
src/sh/ffi.c src/sh/sysv.S \
|
||||
src/sh64/ffi.c src/sh64/sysv.S \
|
||||
src/sparc/ffi.c src/sparc/ffi64.c src/sparc/v8.S src/sparc/v9.S \
|
||||
src/tile/ffi.c src/tile/tile.S \
|
||||
src/vax/ffi.c src/vax/elfbsd.S \
|
||||
src/x86/ffi.c src/x86/sysv.S \
|
||||
src/x86/ffiw64.c src/x86/win64.S \
|
||||
src/x86/ffi64.c src/x86/unix64.S \
|
||||
src/x86/darwin64.S src/x86/darwin.S \
|
||||
src/x86/darwin64_c.c src/x86/darwin_c.c \
|
||||
src/xtensa/ffi.c src/xtensa/sysv.S
|
||||
EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S \
|
||||
src/aarch64/win64_armasm.S src/alpha/ffi.c src/alpha/osf.S \
|
||||
src/arc/ffi.c src/arc/arcompact.S src/arm/ffi.c \
|
||||
src/arm/sysv.S src/arm/ffi.c src/arm/sysv_msvc_arm32.S \
|
||||
src/avr32/ffi.c src/avr32/sysv.S src/bfin/ffi.c \
|
||||
src/bfin/sysv.S src/cris/ffi.c src/cris/sysv.S src/frv/ffi.c \
|
||||
src/csky/ffi.c src/csky/sysv.S src/frv/eabi.S src/ia64/ffi.c \
|
||||
src/ia64/unix.S src/m32r/ffi.c src/m32r/sysv.S src/m68k/ffi.c \
|
||||
src/m68k/sysv.S src/m88k/ffi.c src/m88k/obsd.S \
|
||||
src/metag/ffi.c src/metag/sysv.S src/microblaze/ffi.c \
|
||||
src/microblaze/sysv.S src/mips/ffi.c src/mips/o32.S \
|
||||
src/mips/n32.S src/moxie/ffi.c src/moxie/eabi.S \
|
||||
src/nios2/ffi.c src/nios2/sysv.S src/or1k/ffi.c \
|
||||
src/or1k/sysv.S src/pa/ffi.c src/pa/linux.S src/pa/hpux32.S \
|
||||
src/powerpc/ffi.c src/powerpc/ffi_sysv.c \
|
||||
src/powerpc/ffi_linux64.c src/powerpc/sysv.S \
|
||||
src/powerpc/linux64.S src/powerpc/linux64_closure.S \
|
||||
src/powerpc/ppc_closure.S src/powerpc/aix.S \
|
||||
src/powerpc/darwin.S src/powerpc/aix_closure.S \
|
||||
src/powerpc/darwin_closure.S src/powerpc/ffi_darwin.c \
|
||||
src/riscv/ffi.c src/riscv/sysv.S src/s390/ffi.c \
|
||||
src/s390/sysv.S src/sh/ffi.c src/sh/sysv.S src/sh64/ffi.c \
|
||||
src/sh64/sysv.S src/sparc/ffi.c src/sparc/ffi64.c \
|
||||
src/sparc/v8.S src/sparc/v9.S src/tile/ffi.c src/tile/tile.S \
|
||||
src/vax/ffi.c src/vax/elfbsd.S src/x86/ffi.c src/x86/sysv.S \
|
||||
src/x86/ffiw64.c src/x86/win64.S src/x86/ffi64.c \
|
||||
src/x86/unix64.S src/x86/sysv_intel.S src/x86/win64_intel.S \
|
||||
src/xtensa/ffi.c src/xtensa/sysv.S src/kvx/ffi.c \
|
||||
src/kvx/sysv.S
|
||||
|
||||
TARGET_OBJ = @TARGET_OBJ@
|
||||
libffi_la_LIBADD = $(TARGET_OBJ)
|
||||
|
@ -200,26 +104,26 @@ libffi_convenience_la_LIBADD = $(libffi_la_LIBADD)
|
|||
libffi_convenience_la_DEPENDENCIES = $(libffi_la_DEPENDENCIES)
|
||||
nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
|
||||
|
||||
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
|
||||
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/libtool-ldflags $(LDFLAGS))
|
||||
|
||||
AM_CFLAGS = -Wall -g -fexceptions
|
||||
AM_CFLAGS =
|
||||
if FFI_DEBUG
|
||||
# Build debug. Define FFI_DEBUG on the commandline so that, when building with
|
||||
# MSVC, it can link against the debug CRT.
|
||||
AM_CFLAGS += -DFFI_DEBUG
|
||||
endif
|
||||
|
||||
if LIBAT_BUILD_VERSIONED_SHLIB
|
||||
if LIBAT_BUILD_VERSIONED_SHLIB_GNU
|
||||
if LIBFFI_BUILD_VERSIONED_SHLIB
|
||||
if LIBFFI_BUILD_VERSIONED_SHLIB_GNU
|
||||
libffi_version_script = -Wl,--version-script,libffi.map
|
||||
libffi_version_dep = libffi.map
|
||||
endif
|
||||
if LIBAT_BUILD_VERSIONED_SHLIB_SUN
|
||||
if LIBFFI_BUILD_VERSIONED_SHLIB_SUN
|
||||
libffi_version_script = -Wl,-M,libffi.map-sun
|
||||
libffi_version_dep = libffi.map-sun
|
||||
libffi.map-sun : libffi.map $(top_srcdir)/../contrib/make_sunver.pl \
|
||||
$(libffi_la_OBJECTS) $(libffi_la_LIBADD)
|
||||
perl $(top_srcdir)/../contrib/make_sunver.pl libffi.map \
|
||||
libffi.map-sun : libffi.map $(top_srcdir)/make_sunver.pl \
|
||||
$(libffi_la_OBJECTS) $(libffi_la_LIBADD)
|
||||
perl $(top_srcdir)/make_sunver.pl libffi.map \
|
||||
`echo $(libffi_la_OBJECTS) $(libffi_la_LIBADD) | \
|
||||
sed 's,\([^/ ]*\)\.l\([ao]\),.libs/\1.\2,g'` \
|
||||
> $@ || (rm -f $@ ; exit 1)
|
||||
|
@ -231,7 +135,8 @@ endif
|
|||
libffi_version_info = -version-info `grep -v '^\#' $(srcdir)/libtool-version`
|
||||
|
||||
libffi.map: $(top_srcdir)/libffi.map.in
|
||||
$(COMPILE) -D$(TARGET) -E -x assembler-with-cpp -o $@ $<
|
||||
$(COMPILE) -D$(TARGET) -DGENERATE_LIBFFI_MAP \
|
||||
-E -x assembler-with-cpp -o $@ $(top_srcdir)/libffi.map.in
|
||||
|
||||
libffi_la_LDFLAGS = -no-undefined $(libffi_version_info) $(libffi_version_script) $(LTLDFLAGS) $(AM_LTLDFLAGS)
|
||||
libffi_la_DEPENDENCIES = $(libffi_la_LIBADD) $(libffi_version_dep)
|
||||
|
@ -239,12 +144,8 @@ libffi_la_DEPENDENCIES = $(libffi_la_LIBADD) $(libffi_version_dep)
|
|||
AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src
|
||||
AM_CCASFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
# Multilib support. Automake should provide these on its own.
|
||||
all-recursive: all-multi
|
||||
install-recursive: install-multi
|
||||
mostlyclean-recursive: mostlyclean-multi
|
||||
clean-recursive: clean-multi
|
||||
distclean-recursive: distclean-multi
|
||||
maintainer-clean-recursive: maintainer-clean-multi
|
||||
dist-hook:
|
||||
d=`(cd $(distdir); pwd)`; (cd doc; make pdf; cp *.pdf $$d/doc)
|
||||
if [ -d $(top_srcdir)/.git ] ; then (cd $(top_srcdir); git log --no-decorate) ; else echo 'See git log for history.' ; fi > $(distdir)/ChangeLog
|
||||
s=`awk '/was released on/{ print NR; exit}' $(top_srcdir)/README.md`; tail -n +$$(($$s-1)) $(top_srcdir)/README.md > $(distdir)/README.md
|
||||
|
||||
include $(top_srcdir)/../multilib.am
|
||||
|
|
1944
libffi/Makefile.in
1944
libffi/Makefile.in
File diff suppressed because it is too large
Load diff
450
libffi/README
450
libffi/README
|
@ -1,450 +0,0 @@
|
|||
Status
|
||||
======
|
||||
|
||||
libffi-4?? was released on TBD. Check the libffi web
|
||||
page for updates: <URL:http://sourceware.org/libffi/>.
|
||||
|
||||
|
||||
What is libffi?
|
||||
===============
|
||||
|
||||
Compilers for high level languages generate code that follow certain
|
||||
conventions. These conventions are necessary, in part, for separate
|
||||
compilation to work. One such convention is the "calling
|
||||
convention". The "calling convention" is essentially a set of
|
||||
assumptions made by the compiler about where function arguments will
|
||||
be found on entry to a function. A "calling convention" also specifies
|
||||
where the return value for a function is found.
|
||||
|
||||
Some programs may not know at the time of compilation what arguments
|
||||
are to be passed to a function. For instance, an interpreter may be
|
||||
told at run-time about the number and types of arguments used to call
|
||||
a given function. Libffi can be used in such programs to provide a
|
||||
bridge from the interpreter program to compiled code.
|
||||
|
||||
The libffi library provides a portable, high level programming
|
||||
interface to various calling conventions. This allows a programmer to
|
||||
call any function specified by a call interface description at run
|
||||
time.
|
||||
|
||||
FFI stands for Foreign Function Interface. A foreign function
|
||||
interface is the popular name for the interface that allows code
|
||||
written in one language to call code written in another language. The
|
||||
libffi library really only provides the lowest, machine dependent
|
||||
layer of a fully featured foreign function interface. A layer must
|
||||
exist above libffi that handles type conversions for values passed
|
||||
between the two languages.
|
||||
|
||||
|
||||
Supported Platforms
|
||||
===================
|
||||
|
||||
Libffi has been ported to many different platforms.
|
||||
For specific configuration details and testing status, please
|
||||
refer to the wiki page here:
|
||||
|
||||
http://www.moxielogic.org/wiki/index.php?title=Libffi_3.2
|
||||
|
||||
At the time of release, the following basic configurations have been
|
||||
tested:
|
||||
|
||||
|-----------------+------------------+-------------------------|
|
||||
| Architecture | Operating System | Compiler |
|
||||
|-----------------+------------------+-------------------------|
|
||||
| AArch64 (ARM64) | iOS | Clang |
|
||||
| AArch64 | Linux | GCC |
|
||||
| Alpha | Linux | GCC |
|
||||
| Alpha | Tru64 | GCC |
|
||||
| ARC | Linux | GCC |
|
||||
| ARM | Linux | GCC |
|
||||
| ARM | iOS | GCC |
|
||||
| AVR32 | Linux | GCC |
|
||||
| Blackfin | uClinux | GCC |
|
||||
| HPPA | HPUX | GCC |
|
||||
| IA-64 | Linux | GCC |
|
||||
| M68K | FreeMiNT | GCC |
|
||||
| M68K | Linux | GCC |
|
||||
| M68K | RTEMS | GCC |
|
||||
| M88K | OpenBSD/mvme88k | GCC |
|
||||
| Meta | Linux | GCC |
|
||||
| MicroBlaze | Linux | GCC |
|
||||
| MIPS | IRIX | GCC |
|
||||
| MIPS | Linux | GCC |
|
||||
| MIPS | RTEMS | GCC |
|
||||
| MIPS64 | Linux | GCC |
|
||||
| Moxie | Bare metal | GCC |
|
||||
| Nios II | Linux | GCC |
|
||||
| OpenRISC | Linux | GCC |
|
||||
| PowerPC 32-bit | AIX | IBM XL C |
|
||||
| PowerPC 64-bit | AIX | IBM XL C |
|
||||
| PowerPC | AMIGA | GCC |
|
||||
| PowerPC | Linux | GCC |
|
||||
| PowerPC | Mac OSX | GCC |
|
||||
| PowerPC | FreeBSD | GCC |
|
||||
| PowerPC 64-bit | FreeBSD | GCC |
|
||||
| PowerPC 64-bit | Linux ELFv1 | GCC |
|
||||
| PowerPC 64-bit | Linux ELFv2 | GCC |
|
||||
| S390 | Linux | GCC |
|
||||
| S390X | Linux | GCC |
|
||||
| SPARC | Linux | GCC |
|
||||
| SPARC | Solaris | GCC |
|
||||
| SPARC | Solaris | Oracle Solaris Studio C |
|
||||
| SPARC64 | Linux | GCC |
|
||||
| SPARC64 | FreeBSD | GCC |
|
||||
| SPARC64 | Solaris | Oracle Solaris Studio C |
|
||||
| TILE-Gx/TILEPro | Linux | GCC |
|
||||
| VAX | OpenBSD/vax | GCC |
|
||||
| X86 | FreeBSD | GCC |
|
||||
| X86 | GNU HURD | GCC |
|
||||
| X86 | Interix | GCC |
|
||||
| X86 | kFreeBSD | GCC |
|
||||
| X86 | Linux | GCC |
|
||||
| X86 | Mac OSX | GCC |
|
||||
| X86 | OpenBSD | GCC |
|
||||
| X86 | OS/2 | GCC |
|
||||
| X86 | Solaris | GCC |
|
||||
| X86 | Solaris | Oracle Solaris Studio C |
|
||||
| X86 | Windows/Cygwin | GCC |
|
||||
| X86 | Windows/MingW | GCC |
|
||||
| X86-64 | FreeBSD | GCC |
|
||||
| X86-64 | Linux | GCC |
|
||||
| X86-64 | Linux/x32 | GCC |
|
||||
| X86-64 | OpenBSD | GCC |
|
||||
| X86-64 | Solaris | Oracle Solaris Studio C |
|
||||
| X86-64 | Windows/Cygwin | GCC |
|
||||
| X86-64 | Windows/MingW | GCC |
|
||||
| Xtensa | Linux | GCC |
|
||||
|-----------------+------------------+-------------------------|
|
||||
|
||||
Please send additional platform test results to
|
||||
libffi-discuss@sourceware.org and feel free to update the wiki page
|
||||
above.
|
||||
|
||||
Installing libffi
|
||||
=================
|
||||
|
||||
First you must configure the distribution for your particular
|
||||
system. Go to the directory you wish to build libffi in and run the
|
||||
"configure" program found in the root directory of the libffi source
|
||||
distribution.
|
||||
|
||||
If you're building libffi directly from version control, configure won't
|
||||
exist yet; run ./autogen.sh first.
|
||||
|
||||
You may want to tell configure where to install the libffi library and
|
||||
header files. To do that, use the --prefix configure switch. Libffi
|
||||
will install under /usr/local by default.
|
||||
|
||||
If you want to enable extra run-time debugging checks use the the
|
||||
--enable-debug configure switch. This is useful when your program dies
|
||||
mysteriously while using libffi.
|
||||
|
||||
Another useful configure switch is --enable-purify-safety. Using this
|
||||
will add some extra code which will suppress certain warnings when you
|
||||
are using Purify with libffi. Only use this switch when using
|
||||
Purify, as it will slow down the library.
|
||||
|
||||
It's also possible to build libffi on Windows platforms with
|
||||
Microsoft's Visual C++ compiler. In this case, use the msvcc.sh
|
||||
wrapper script during configuration like so:
|
||||
|
||||
path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP="cl -nologo -EP"
|
||||
|
||||
For 64-bit Windows builds, use CC="path/to/msvcc.sh -m64" and
|
||||
CXX="path/to/msvcc.sh -m64". You may also need to specify --build
|
||||
appropriately.
|
||||
|
||||
It is also possible to build libffi on Windows platforms with the LLVM
|
||||
project's clang-cl compiler, like below:
|
||||
|
||||
path/to/configure CC="path/to/msvcc.sh -clang-cl" CXX="path/to/msvcc.sh -clang-cl" LD=link CPP="clang-cl -EP"
|
||||
|
||||
When building with MSVC under a MingW environment, you may need to
|
||||
remove the line in configure that sets 'fix_srcfile_path' to a 'cygpath'
|
||||
command. ('cygpath' is not present in MingW, and is not required when
|
||||
using MingW-style paths.)
|
||||
|
||||
For iOS builds, the 'libffi.xcodeproj' Xcode project is available.
|
||||
|
||||
Configure has many other options. Use "configure --help" to see them all.
|
||||
|
||||
Once configure has finished, type "make". Note that you must be using
|
||||
GNU make. You can ftp GNU make from ftp.gnu.org:/pub/gnu/make .
|
||||
|
||||
To ensure that libffi is working as advertised, type "make check".
|
||||
This will require that you have DejaGNU installed.
|
||||
|
||||
To install the library and header files, type "make install".
|
||||
|
||||
|
||||
History
|
||||
=======
|
||||
|
||||
See the git log for details at http://github.com/atgreen/libffi.
|
||||
|
||||
4.0 TBD
|
||||
New API in support of GO closures.
|
||||
|
||||
3.2.1 Nov-12-14
|
||||
Build fix for non-iOS AArch64 targets.
|
||||
|
||||
3.2 Nov-11-14
|
||||
Add C99 Complex Type support (currently only supported on
|
||||
s390).
|
||||
Add support for PASCAL and REGISTER calling conventions on x86
|
||||
Windows/Linux.
|
||||
Add OpenRISC and Cygwin-64 support.
|
||||
Bug fixes.
|
||||
|
||||
3.1 May-19-14
|
||||
Add AArch64 (ARM64) iOS support.
|
||||
Add Nios II support.
|
||||
Add m88k and DEC VAX support.
|
||||
Add support for stdcall, thiscall, and fastcall on non-Windows
|
||||
32-bit x86 targets such as Linux.
|
||||
Various Android, MIPS N32, x86, FreeBSD and UltraSPARC IIi
|
||||
fixes.
|
||||
Make the testsuite more robust: eliminate several spurious
|
||||
failures, and respect the $CC and $CXX environment variables.
|
||||
Archive off the manually maintained ChangeLog in favor of git
|
||||
log.
|
||||
|
||||
3.0.13 Mar-17-13
|
||||
Add Meta support.
|
||||
Add missing Moxie bits.
|
||||
Fix stack alignment bug on 32-bit x86.
|
||||
Build fix for m68000 targets.
|
||||
Build fix for soft-float Power targets.
|
||||
Fix the install dir location for some platforms when building
|
||||
with GCC (OS X, Solaris).
|
||||
Fix Cygwin regression.
|
||||
|
||||
3.0.12 Feb-11-13
|
||||
Add Moxie support.
|
||||
Add AArch64 support.
|
||||
Add Blackfin support.
|
||||
Add TILE-Gx/TILEPro support.
|
||||
Add MicroBlaze support.
|
||||
Add Xtensa support.
|
||||
Add support for PaX enabled kernels with MPROTECT.
|
||||
Add support for native vendor compilers on
|
||||
Solaris and AIX.
|
||||
Work around LLVM/GCC interoperability issue on x86_64.
|
||||
|
||||
3.0.11 Apr-11-12
|
||||
Lots of build fixes.
|
||||
Add support for variadic functions (ffi_prep_cif_var).
|
||||
Add Linux/x32 support.
|
||||
Add thiscall, fastcall and MSVC cdecl support on Windows.
|
||||
Add Amiga and newer MacOS support.
|
||||
Add m68k FreeMiNT support.
|
||||
Integration with iOS' xcode build tools.
|
||||
Fix Octeon and MC68881 support.
|
||||
Fix code pessimizations.
|
||||
|
||||
3.0.10 Aug-23-11
|
||||
Add support for Apple's iOS.
|
||||
Add support for ARM VFP ABI.
|
||||
Add RTEMS support for MIPS and M68K.
|
||||
Fix instruction cache clearing problems on
|
||||
ARM and SPARC.
|
||||
Fix the N64 build on mips-sgi-irix6.5.
|
||||
Enable builds with Microsoft's compiler.
|
||||
Enable x86 builds with Oracle's Solaris compiler.
|
||||
Fix support for calling code compiled with Oracle's Sparc
|
||||
Solaris compiler.
|
||||
Testsuite fixes for Tru64 Unix.
|
||||
Additional platform support.
|
||||
|
||||
3.0.9 Dec-31-09
|
||||
Add AVR32 and win64 ports. Add ARM softfp support.
|
||||
Many fixes for AIX, Solaris, HP-UX, *BSD.
|
||||
Several PowerPC and x86-64 bug fixes.
|
||||
Build DLL for windows.
|
||||
|
||||
3.0.8 Dec-19-08
|
||||
Add *BSD, BeOS, and PA-Linux support.
|
||||
|
||||
3.0.7 Nov-11-08
|
||||
Fix for ppc FreeBSD.
|
||||
(thanks to Andreas Tobler)
|
||||
|
||||
3.0.6 Jul-17-08
|
||||
Fix for closures on sh.
|
||||
Mark the sh/sh64 stack as non-executable.
|
||||
(both thanks to Kaz Kojima)
|
||||
|
||||
3.0.5 Apr-3-08
|
||||
Fix libffi.pc file.
|
||||
Fix #define ARM for IcedTea users.
|
||||
Fix x86 closure bug.
|
||||
|
||||
3.0.4 Feb-24-08
|
||||
Fix x86 OpenBSD configury.
|
||||
|
||||
3.0.3 Feb-22-08
|
||||
Enable x86 OpenBSD thanks to Thomas Heller, and
|
||||
x86-64 FreeBSD thanks to Björn König and Andreas Tobler.
|
||||
Clean up test instruction in README.
|
||||
|
||||
3.0.2 Feb-21-08
|
||||
Improved x86 FreeBSD support.
|
||||
Thanks to Björn König.
|
||||
|
||||
3.0.1 Feb-15-08
|
||||
Fix instruction cache flushing bug on MIPS.
|
||||
Thanks to David Daney.
|
||||
|
||||
3.0.0 Feb-15-08
|
||||
Many changes, mostly thanks to the GCC project.
|
||||
Cygnus Solutions is now Red Hat.
|
||||
|
||||
[10 years go by...]
|
||||
|
||||
1.20 Oct-5-98
|
||||
Raffaele Sena produces ARM port.
|
||||
|
||||
1.19 Oct-5-98
|
||||
Fixed x86 long double and long long return support.
|
||||
m68k bug fixes from Andreas Schwab.
|
||||
Patch for DU assembler compatibility for the Alpha from Richard
|
||||
Henderson.
|
||||
|
||||
1.18 Apr-17-98
|
||||
Bug fixes and MIPS configuration changes.
|
||||
|
||||
1.17 Feb-24-98
|
||||
Bug fixes and m68k port from Andreas Schwab. PowerPC port from
|
||||
Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes.
|
||||
|
||||
1.16 Feb-11-98
|
||||
Richard Henderson produces Alpha port.
|
||||
|
||||
1.15 Dec-4-97
|
||||
Fixed an n32 ABI bug. New libtool, auto* support.
|
||||
|
||||
1.14 May-13-97
|
||||
libtool is now used to generate shared and static libraries.
|
||||
Fixed a minor portability problem reported by Russ McManus
|
||||
<mcmanr@eq.gs.com>.
|
||||
|
||||
1.13 Dec-2-96
|
||||
Added --enable-purify-safety to keep Purify from complaining
|
||||
about certain low level code.
|
||||
Sparc fix for calling functions with < 6 args.
|
||||
Linux x86 a.out fix.
|
||||
|
||||
1.12 Nov-22-96
|
||||
Added missing ffi_type_void, needed for supporting void return
|
||||
types. Fixed test case for non MIPS machines. Cygnus Support
|
||||
is now Cygnus Solutions.
|
||||
|
||||
1.11 Oct-30-96
|
||||
Added notes about GNU make.
|
||||
|
||||
1.10 Oct-29-96
|
||||
Added configuration fix for non GNU compilers.
|
||||
|
||||
1.09 Oct-29-96
|
||||
Added --enable-debug configure switch. Clean-ups based on LCLint
|
||||
feedback. ffi_mips.h is always installed. Many configuration
|
||||
fixes. Fixed ffitest.c for sparc builds.
|
||||
|
||||
1.08 Oct-15-96
|
||||
Fixed n32 problem. Many clean-ups.
|
||||
|
||||
1.07 Oct-14-96
|
||||
Gordon Irlam rewrites v8.S again. Bug fixes.
|
||||
|
||||
1.06 Oct-14-96
|
||||
Gordon Irlam improved the sparc port.
|
||||
|
||||
1.05 Oct-14-96
|
||||
Interface changes based on feedback.
|
||||
|
||||
1.04 Oct-11-96
|
||||
Sparc port complete (modulo struct passing bug).
|
||||
|
||||
1.03 Oct-10-96
|
||||
Passing struct args, and returning struct values works for
|
||||
all architectures/calling conventions. Expanded tests.
|
||||
|
||||
1.02 Oct-9-96
|
||||
Added SGI n32 support. Fixed bugs in both o32 and Linux support.
|
||||
Added "make test".
|
||||
|
||||
1.01 Oct-8-96
|
||||
Fixed float passing bug in mips version. Restructured some
|
||||
of the code. Builds cleanly with SGI tools.
|
||||
|
||||
1.00 Oct-7-96
|
||||
First release. No public announcement.
|
||||
|
||||
|
||||
Authors & Credits
|
||||
=================
|
||||
|
||||
libffi was originally written by Anthony Green <green@moxielogic.com>.
|
||||
|
||||
The developers of the GNU Compiler Collection project have made
|
||||
innumerable valuable contributions. See the ChangeLog file for
|
||||
details.
|
||||
|
||||
Some of the ideas behind libffi were inspired by Gianni Mariani's free
|
||||
gencall library for Silicon Graphics machines.
|
||||
|
||||
The closure mechanism was designed and implemented by Kresten Krab
|
||||
Thorup.
|
||||
|
||||
Major processor architecture ports were contributed by the following
|
||||
developers:
|
||||
|
||||
aarch64 Marcus Shawcroft, James Greenhalgh
|
||||
alpha Richard Henderson
|
||||
arm Raffaele Sena
|
||||
blackfin Alexandre Keunecke I. de Mendonca
|
||||
cris Simon Posnjak, Hans-Peter Nilsson
|
||||
frv Anthony Green
|
||||
ia64 Hans Boehm
|
||||
m32r Kazuhiro Inaoka
|
||||
m68k Andreas Schwab
|
||||
m88k Miod Vallat
|
||||
microblaze Nathan Rossi
|
||||
mips Anthony Green, Casey Marshall
|
||||
mips64 David Daney
|
||||
moxie Anthony Green
|
||||
nios ii Sandra Loosemore
|
||||
openrisc Sebastian Macke
|
||||
pa Randolph Chung, Dave Anglin, Andreas Tobler
|
||||
powerpc Geoffrey Keating, Andreas Tobler,
|
||||
David Edelsohn, John Hornkvist
|
||||
powerpc64 Jakub Jelinek
|
||||
s390 Gerhard Tonn, Ulrich Weigand
|
||||
sh Kaz Kojima
|
||||
sh64 Kaz Kojima
|
||||
sparc Anthony Green, Gordon Irlam
|
||||
tile-gx/tilepro Walter Lee
|
||||
vax Miod Vallat
|
||||
x86 Anthony Green, Jon Beniston
|
||||
x86-64 Bo Thorsen
|
||||
xtensa Chris Zankel
|
||||
|
||||
Jesper Skov and Andrew Haley both did more than their fair share of
|
||||
stepping through the code and tracking down bugs.
|
||||
|
||||
Thanks also to Tom Tromey for bug fixes, documentation and
|
||||
configuration help.
|
||||
|
||||
Thanks to Jim Blandy, who provided some useful feedback on the libffi
|
||||
interface.
|
||||
|
||||
Andreas Tobler has done a tremendous amount of work on the testsuite.
|
||||
|
||||
Alex Oliva solved the executable page problem for SElinux.
|
||||
|
||||
The list above is almost certainly incomplete and inaccurate. I'm
|
||||
happy to make corrections or additions upon request.
|
||||
|
||||
If you have a problem, or have found a bug, please send a note to the
|
||||
author at green@moxielogic.com, or the project mailing list at
|
||||
libffi-discuss@sourceware.org.
|
495
libffi/README.md
Normal file
495
libffi/README.md
Normal file
|
@ -0,0 +1,495 @@
|
|||
Status
|
||||
======
|
||||
|
||||
libffi-3.4.1 was released on June 28, 2021. Check the libffi web page
|
||||
for updates: <URL:http://sourceware.org/libffi/>.
|
||||
|
||||
|
||||
What is libffi?
|
||||
===============
|
||||
|
||||
Compilers for high level languages generate code that follow certain
|
||||
conventions. These conventions are necessary, in part, for separate
|
||||
compilation to work. One such convention is the "calling
|
||||
convention". The "calling convention" is essentially a set of
|
||||
assumptions made by the compiler about where function arguments will
|
||||
be found on entry to a function. A "calling convention" also specifies
|
||||
where the return value for a function is found.
|
||||
|
||||
Some programs may not know at the time of compilation what arguments
|
||||
are to be passed to a function. For instance, an interpreter may be
|
||||
told at run-time about the number and types of arguments used to call
|
||||
a given function. Libffi can be used in such programs to provide a
|
||||
bridge from the interpreter program to compiled code.
|
||||
|
||||
The libffi library provides a portable, high level programming
|
||||
interface to various calling conventions. This allows a programmer to
|
||||
call any function specified by a call interface description at run
|
||||
time.
|
||||
|
||||
FFI stands for Foreign Function Interface. A foreign function
|
||||
interface is the popular name for the interface that allows code
|
||||
written in one language to call code written in another language. The
|
||||
libffi library really only provides the lowest, machine dependent
|
||||
layer of a fully featured foreign function interface. A layer must
|
||||
exist above libffi that handles type conversions for values passed
|
||||
between the two languages.
|
||||
|
||||
|
||||
Supported Platforms
|
||||
===================
|
||||
|
||||
Libffi has been ported to many different platforms.
|
||||
|
||||
At the time of release, the following basic configurations have been
|
||||
tested:
|
||||
|
||||
| Architecture | Operating System | Compiler |
|
||||
| --------------- | ---------------- | ----------------------- |
|
||||
| AArch64 (ARM64) | iOS | Clang |
|
||||
| AArch64 | Linux | GCC |
|
||||
| AArch64 | Windows | MSVC |
|
||||
| Alpha | Linux | GCC |
|
||||
| Alpha | Tru64 | GCC |
|
||||
| ARC | Linux | GCC |
|
||||
| ARM | Linux | GCC |
|
||||
| ARM | iOS | GCC |
|
||||
| ARM | Windows | MSVC |
|
||||
| AVR32 | Linux | GCC |
|
||||
| Blackfin | uClinux | GCC |
|
||||
| CSKY | Linux | GCC |
|
||||
| HPPA | HPUX | GCC |
|
||||
| KVX | Linux | GCC |
|
||||
| IA-64 | Linux | GCC |
|
||||
| M68K | FreeMiNT | GCC |
|
||||
| M68K | Linux | GCC |
|
||||
| M68K | RTEMS | GCC |
|
||||
| M88K | OpenBSD/mvme88k | GCC |
|
||||
| Meta | Linux | GCC |
|
||||
| MicroBlaze | Linux | GCC |
|
||||
| MIPS | IRIX | GCC |
|
||||
| MIPS | Linux | GCC |
|
||||
| MIPS | RTEMS | GCC |
|
||||
| MIPS64 | Linux | GCC |
|
||||
| Moxie | Bare metal | GCC |
|
||||
| Nios II | Linux | GCC |
|
||||
| OpenRISC | Linux | GCC |
|
||||
| PowerPC 32-bit | AIX | IBM XL C |
|
||||
| PowerPC 64-bit | AIX | IBM XL C |
|
||||
| PowerPC | AMIGA | GCC |
|
||||
| PowerPC | Linux | GCC |
|
||||
| PowerPC | Mac OSX | GCC |
|
||||
| PowerPC | FreeBSD | GCC |
|
||||
| PowerPC 64-bit | FreeBSD | GCC |
|
||||
| PowerPC 64-bit | Linux ELFv1 | GCC |
|
||||
| PowerPC 64-bit | Linux ELFv2 | GCC |
|
||||
| RISC-V 32-bit | Linux | GCC |
|
||||
| RISC-V 64-bit | Linux | GCC |
|
||||
| S390 | Linux | GCC |
|
||||
| S390X | Linux | GCC |
|
||||
| SPARC | Linux | GCC |
|
||||
| SPARC | Solaris | GCC |
|
||||
| SPARC | Solaris | Oracle Solaris Studio C |
|
||||
| SPARC64 | Linux | GCC |
|
||||
| SPARC64 | FreeBSD | GCC |
|
||||
| SPARC64 | Solaris | Oracle Solaris Studio C |
|
||||
| TILE-Gx/TILEPro | Linux | GCC |
|
||||
| VAX | OpenBSD/vax | GCC |
|
||||
| X86 | FreeBSD | GCC |
|
||||
| X86 | GNU HURD | GCC |
|
||||
| X86 | Interix | GCC |
|
||||
| X86 | kFreeBSD | GCC |
|
||||
| X86 | Linux | GCC |
|
||||
| X86 | OpenBSD | GCC |
|
||||
| X86 | OS/2 | GCC |
|
||||
| X86 | Solaris | GCC |
|
||||
| X86 | Solaris | Oracle Solaris Studio C |
|
||||
| X86 | Windows/Cygwin | GCC |
|
||||
| X86 | Windows/MingW | GCC |
|
||||
| X86-64 | FreeBSD | GCC |
|
||||
| X86-64 | Linux | GCC |
|
||||
| X86-64 | Linux/x32 | GCC |
|
||||
| X86-64 | OpenBSD | GCC |
|
||||
| X86-64 | Solaris | Oracle Solaris Studio C |
|
||||
| X86-64 | Windows/Cygwin | GCC |
|
||||
| X86-64 | Windows/MingW | GCC |
|
||||
| X86-64 | Mac OSX | GCC |
|
||||
| Xtensa | Linux | GCC |
|
||||
|
||||
Please send additional platform test results to
|
||||
libffi-discuss@sourceware.org.
|
||||
|
||||
Installing libffi
|
||||
=================
|
||||
|
||||
First you must configure the distribution for your particular
|
||||
system. Go to the directory you wish to build libffi in and run the
|
||||
"configure" program found in the root directory of the libffi source
|
||||
distribution. Note that building libffi requires a C99 compatible
|
||||
compiler.
|
||||
|
||||
If you're building libffi directly from git hosted sources, configure
|
||||
won't exist yet; run ./autogen.sh first. This will require that you
|
||||
install autoconf, automake and libtool.
|
||||
|
||||
You may want to tell configure where to install the libffi library and
|
||||
header files. To do that, use the ``--prefix`` configure switch. Libffi
|
||||
will install under /usr/local by default.
|
||||
|
||||
If you want to enable extra run-time debugging checks use the the
|
||||
``--enable-debug`` configure switch. This is useful when your program dies
|
||||
mysteriously while using libffi.
|
||||
|
||||
Another useful configure switch is ``--enable-purify-safety``. Using this
|
||||
will add some extra code which will suppress certain warnings when you
|
||||
are using Purify with libffi. Only use this switch when using
|
||||
Purify, as it will slow down the library.
|
||||
|
||||
If you don't want to build documentation, use the ``--disable-docs``
|
||||
configure switch.
|
||||
|
||||
It's also possible to build libffi on Windows platforms with
|
||||
Microsoft's Visual C++ compiler. In this case, use the msvcc.sh
|
||||
wrapper script during configuration like so:
|
||||
|
||||
path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP="cl -nologo -EP" CPPFLAGS="-DFFI_BUILDING_DLL"
|
||||
|
||||
For 64-bit Windows builds, use ``CC="path/to/msvcc.sh -m64"`` and
|
||||
``CXX="path/to/msvcc.sh -m64"``. You may also need to specify
|
||||
``--build`` appropriately.
|
||||
|
||||
It is also possible to build libffi on Windows platforms with the LLVM
|
||||
project's clang-cl compiler, like below:
|
||||
|
||||
path/to/configure CC="path/to/msvcc.sh -clang-cl" CXX="path/to/msvcc.sh -clang-cl" LD=link CPP="clang-cl -EP"
|
||||
|
||||
When building with MSVC under a MingW environment, you may need to
|
||||
remove the line in configure that sets 'fix_srcfile_path' to a 'cygpath'
|
||||
command. ('cygpath' is not present in MingW, and is not required when
|
||||
using MingW-style paths.)
|
||||
|
||||
To build static library for ARM64 with MSVC using visual studio solution, msvc_build folder have
|
||||
aarch64/Ffi_staticLib.sln
|
||||
required header files in aarch64/aarch64_include/
|
||||
|
||||
|
||||
SPARC Solaris builds require the use of the GNU assembler and linker.
|
||||
Point ``AS`` and ``LD`` environment variables at those tool prior to
|
||||
configuration.
|
||||
|
||||
For iOS builds, the ``libffi.xcodeproj`` Xcode project is available.
|
||||
|
||||
Configure has many other options. Use ``configure --help`` to see them all.
|
||||
|
||||
Once configure has finished, type "make". Note that you must be using
|
||||
GNU make. You can ftp GNU make from ftp.gnu.org:/pub/gnu/make .
|
||||
|
||||
To ensure that libffi is working as advertised, type "make check".
|
||||
This will require that you have DejaGNU installed.
|
||||
|
||||
To install the library and header files, type ``make install``.
|
||||
|
||||
|
||||
History
|
||||
=======
|
||||
|
||||
See the git log for details at http://github.com/libffi/libffi.
|
||||
|
||||
3.4.2 Jun-28-21
|
||||
Add static trampoline support for Linux on x86_64 and ARM64.
|
||||
Add support for Alibaba's CSKY architecture.
|
||||
Add support for Kalray's KVX architecture.
|
||||
Add support for Intel Control-flow Enforcement Technology (CET).
|
||||
Add support for ARM Pointer Authentication (PA).
|
||||
Fix 32-bit PPC regression.
|
||||
Fix MIPS soft-float problem.
|
||||
Enable tmpdir override with the $LIBFFI_TMPDIR environment variable.
|
||||
Enable compatibility with MSVC runtime stack checking.
|
||||
Reject float and small integer argument in ffi_prep_cif_var().
|
||||
Callers must promote these types themselves.
|
||||
|
||||
3.3 Nov-23-19
|
||||
Add RISC-V support.
|
||||
New API in support of GO closures.
|
||||
Add IEEE754 binary128 long double support for 64-bit Power
|
||||
Default to Microsoft's 64 bit long double ABI with Visual C++.
|
||||
GNU compiler uses 80 bits (128 in memory) FFI_GNUW64 ABI.
|
||||
Add Windows on ARM64 (WOA) support.
|
||||
Add Windows 32-bit ARM support.
|
||||
Raw java (gcj) API deprecated.
|
||||
Add pre-built PDF documentation to source distribution.
|
||||
Many new test cases and bug fixes.
|
||||
|
||||
3.2.1 Nov-12-14
|
||||
Build fix for non-iOS AArch64 targets.
|
||||
|
||||
3.2 Nov-11-14
|
||||
Add C99 Complex Type support (currently only supported on
|
||||
s390).
|
||||
Add support for PASCAL and REGISTER calling conventions on x86
|
||||
Windows/Linux.
|
||||
Add OpenRISC and Cygwin-64 support.
|
||||
Bug fixes.
|
||||
|
||||
3.1 May-19-14
|
||||
Add AArch64 (ARM64) iOS support.
|
||||
Add Nios II support.
|
||||
Add m88k and DEC VAX support.
|
||||
Add support for stdcall, thiscall, and fastcall on non-Windows
|
||||
32-bit x86 targets such as Linux.
|
||||
Various Android, MIPS N32, x86, FreeBSD and UltraSPARC IIi
|
||||
fixes.
|
||||
Make the testsuite more robust: eliminate several spurious
|
||||
failures, and respect the $CC and $CXX environment variables.
|
||||
Archive off the manually maintained ChangeLog in favor of git
|
||||
log.
|
||||
|
||||
3.0.13 Mar-17-13
|
||||
Add Meta support.
|
||||
Add missing Moxie bits.
|
||||
Fix stack alignment bug on 32-bit x86.
|
||||
Build fix for m68000 targets.
|
||||
Build fix for soft-float Power targets.
|
||||
Fix the install dir location for some platforms when building
|
||||
with GCC (OS X, Solaris).
|
||||
Fix Cygwin regression.
|
||||
|
||||
3.0.12 Feb-11-13
|
||||
Add Moxie support.
|
||||
Add AArch64 support.
|
||||
Add Blackfin support.
|
||||
Add TILE-Gx/TILEPro support.
|
||||
Add MicroBlaze support.
|
||||
Add Xtensa support.
|
||||
Add support for PaX enabled kernels with MPROTECT.
|
||||
Add support for native vendor compilers on
|
||||
Solaris and AIX.
|
||||
Work around LLVM/GCC interoperability issue on x86_64.
|
||||
|
||||
3.0.11 Apr-11-12
|
||||
Lots of build fixes.
|
||||
Add support for variadic functions (ffi_prep_cif_var).
|
||||
Add Linux/x32 support.
|
||||
Add thiscall, fastcall and MSVC cdecl support on Windows.
|
||||
Add Amiga and newer MacOS support.
|
||||
Add m68k FreeMiNT support.
|
||||
Integration with iOS' xcode build tools.
|
||||
Fix Octeon and MC68881 support.
|
||||
Fix code pessimizations.
|
||||
|
||||
3.0.10 Aug-23-11
|
||||
Add support for Apple's iOS.
|
||||
Add support for ARM VFP ABI.
|
||||
Add RTEMS support for MIPS and M68K.
|
||||
Fix instruction cache clearing problems on
|
||||
ARM and SPARC.
|
||||
Fix the N64 build on mips-sgi-irix6.5.
|
||||
Enable builds with Microsoft's compiler.
|
||||
Enable x86 builds with Oracle's Solaris compiler.
|
||||
Fix support for calling code compiled with Oracle's Sparc
|
||||
Solaris compiler.
|
||||
Testsuite fixes for Tru64 Unix.
|
||||
Additional platform support.
|
||||
|
||||
3.0.9 Dec-31-09
|
||||
Add AVR32 and win64 ports. Add ARM softfp support.
|
||||
Many fixes for AIX, Solaris, HP-UX, *BSD.
|
||||
Several PowerPC and x86-64 bug fixes.
|
||||
Build DLL for windows.
|
||||
|
||||
3.0.8 Dec-19-08
|
||||
Add *BSD, BeOS, and PA-Linux support.
|
||||
|
||||
3.0.7 Nov-11-08
|
||||
Fix for ppc FreeBSD.
|
||||
(thanks to Andreas Tobler)
|
||||
|
||||
3.0.6 Jul-17-08
|
||||
Fix for closures on sh.
|
||||
Mark the sh/sh64 stack as non-executable.
|
||||
(both thanks to Kaz Kojima)
|
||||
|
||||
3.0.5 Apr-3-08
|
||||
Fix libffi.pc file.
|
||||
Fix #define ARM for IcedTea users.
|
||||
Fix x86 closure bug.
|
||||
|
||||
3.0.4 Feb-24-08
|
||||
Fix x86 OpenBSD configury.
|
||||
|
||||
3.0.3 Feb-22-08
|
||||
Enable x86 OpenBSD thanks to Thomas Heller, and
|
||||
x86-64 FreeBSD thanks to Björn König and Andreas Tobler.
|
||||
Clean up test instruction in README.
|
||||
|
||||
3.0.2 Feb-21-08
|
||||
Improved x86 FreeBSD support.
|
||||
Thanks to Björn König.
|
||||
|
||||
3.0.1 Feb-15-08
|
||||
Fix instruction cache flushing bug on MIPS.
|
||||
Thanks to David Daney.
|
||||
|
||||
3.0.0 Feb-15-08
|
||||
Many changes, mostly thanks to the GCC project.
|
||||
Cygnus Solutions is now Red Hat.
|
||||
|
||||
[10 years go by...]
|
||||
|
||||
1.20 Oct-5-98
|
||||
Raffaele Sena produces ARM port.
|
||||
|
||||
1.19 Oct-5-98
|
||||
Fixed x86 long double and long long return support.
|
||||
m68k bug fixes from Andreas Schwab.
|
||||
Patch for DU assembler compatibility for the Alpha from Richard
|
||||
Henderson.
|
||||
|
||||
1.18 Apr-17-98
|
||||
Bug fixes and MIPS configuration changes.
|
||||
|
||||
1.17 Feb-24-98
|
||||
Bug fixes and m68k port from Andreas Schwab. PowerPC port from
|
||||
Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes.
|
||||
|
||||
1.16 Feb-11-98
|
||||
Richard Henderson produces Alpha port.
|
||||
|
||||
1.15 Dec-4-97
|
||||
Fixed an n32 ABI bug. New libtool, auto* support.
|
||||
|
||||
1.14 May-13-97
|
||||
libtool is now used to generate shared and static libraries.
|
||||
Fixed a minor portability problem reported by Russ McManus
|
||||
<mcmanr@eq.gs.com>.
|
||||
|
||||
1.13 Dec-2-96
|
||||
Added --enable-purify-safety to keep Purify from complaining
|
||||
about certain low level code.
|
||||
Sparc fix for calling functions with < 6 args.
|
||||
Linux x86 a.out fix.
|
||||
|
||||
1.12 Nov-22-96
|
||||
Added missing ffi_type_void, needed for supporting void return
|
||||
types. Fixed test case for non MIPS machines. Cygnus Support
|
||||
is now Cygnus Solutions.
|
||||
|
||||
1.11 Oct-30-96
|
||||
Added notes about GNU make.
|
||||
|
||||
1.10 Oct-29-96
|
||||
Added configuration fix for non GNU compilers.
|
||||
|
||||
1.09 Oct-29-96
|
||||
Added --enable-debug configure switch. Clean-ups based on LCLint
|
||||
feedback. ffi_mips.h is always installed. Many configuration
|
||||
fixes. Fixed ffitest.c for sparc builds.
|
||||
|
||||
1.08 Oct-15-96
|
||||
Fixed n32 problem. Many clean-ups.
|
||||
|
||||
1.07 Oct-14-96
|
||||
Gordon Irlam rewrites v8.S again. Bug fixes.
|
||||
|
||||
1.06 Oct-14-96
|
||||
Gordon Irlam improved the sparc port.
|
||||
|
||||
1.05 Oct-14-96
|
||||
Interface changes based on feedback.
|
||||
|
||||
1.04 Oct-11-96
|
||||
Sparc port complete (modulo struct passing bug).
|
||||
|
||||
1.03 Oct-10-96
|
||||
Passing struct args, and returning struct values works for
|
||||
all architectures/calling conventions. Expanded tests.
|
||||
|
||||
1.02 Oct-9-96
|
||||
Added SGI n32 support. Fixed bugs in both o32 and Linux support.
|
||||
Added "make test".
|
||||
|
||||
1.01 Oct-8-96
|
||||
Fixed float passing bug in mips version. Restructured some
|
||||
of the code. Builds cleanly with SGI tools.
|
||||
|
||||
1.00 Oct-7-96
|
||||
First release. No public announcement.
|
||||
|
||||
Authors & Credits
|
||||
=================
|
||||
|
||||
libffi was originally written by Anthony Green <green@moxielogic.com>.
|
||||
|
||||
The developers of the GNU Compiler Collection project have made
|
||||
innumerable valuable contributions. See the ChangeLog file for
|
||||
details.
|
||||
|
||||
Some of the ideas behind libffi were inspired by Gianni Mariani's free
|
||||
gencall library for Silicon Graphics machines.
|
||||
|
||||
The closure mechanism was designed and implemented by Kresten Krab
|
||||
Thorup.
|
||||
|
||||
Major processor architecture ports were contributed by the following
|
||||
developers:
|
||||
|
||||
aarch64 Marcus Shawcroft, James Greenhalgh
|
||||
alpha Richard Henderson
|
||||
arc Hackers at Synopsis
|
||||
arm Raffaele Sena
|
||||
avr32 Bradley Smith
|
||||
blackfin Alexandre Keunecke I. de Mendonca
|
||||
cris Simon Posnjak, Hans-Peter Nilsson
|
||||
csky Ma Jun, Zhang Wenmeng
|
||||
frv Anthony Green
|
||||
ia64 Hans Boehm
|
||||
kvx Yann Sionneau
|
||||
m32r Kazuhiro Inaoka
|
||||
m68k Andreas Schwab
|
||||
m88k Miod Vallat
|
||||
metag Hackers at Imagination Technologies
|
||||
microblaze Nathan Rossi
|
||||
mips Anthony Green, Casey Marshall
|
||||
mips64 David Daney
|
||||
moxie Anthony Green
|
||||
nios ii Sandra Loosemore
|
||||
openrisc Sebastian Macke
|
||||
pa Randolph Chung, Dave Anglin, Andreas Tobler
|
||||
powerpc Geoffrey Keating, Andreas Tobler,
|
||||
David Edelsohn, John Hornkvist
|
||||
powerpc64 Jakub Jelinek
|
||||
riscv Michael Knyszek, Andrew Waterman, Stef O'Rear
|
||||
s390 Gerhard Tonn, Ulrich Weigand
|
||||
sh Kaz Kojima
|
||||
sh64 Kaz Kojima
|
||||
sparc Anthony Green, Gordon Irlam
|
||||
tile-gx/tilepro Walter Lee
|
||||
vax Miod Vallat
|
||||
x86 Anthony Green, Jon Beniston
|
||||
x86-64 Bo Thorsen
|
||||
xtensa Chris Zankel
|
||||
|
||||
Jesper Skov and Andrew Haley both did more than their fair share of
|
||||
stepping through the code and tracking down bugs.
|
||||
|
||||
Thanks also to Tom Tromey for bug fixes, documentation and
|
||||
configuration help.
|
||||
|
||||
Thanks to Jim Blandy, who provided some useful feedback on the libffi
|
||||
interface.
|
||||
|
||||
Andreas Tobler has done a tremendous amount of work on the testsuite.
|
||||
|
||||
Alex Oliva solved the executable page problem for SElinux.
|
||||
|
||||
The list above is almost certainly incomplete and inaccurate. I'm
|
||||
happy to make corrections or additions upon request.
|
||||
|
||||
If you have a problem, or have found a bug, please file an issue on
|
||||
our issue tracker at https://github.com/libffi/libffi/issues.
|
||||
|
||||
The author can be reached at green@moxielogic.com.
|
||||
|
||||
To subscribe/unsubscribe to our mailing lists, visit:
|
||||
https://sourceware.org/mailman/listinfo/libffi-announce
|
||||
https://sourceware.org/mailman/listinfo/libffi-discuss
|
|
@ -95,14 +95,14 @@ dnl ----------------------------------------------------------------------
|
|||
dnl This whole bit snagged from libstdc++-v3, via libatomic.
|
||||
|
||||
dnl
|
||||
dnl LIBAT_ENABLE
|
||||
dnl LIBFFI_ENABLE
|
||||
dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING)
|
||||
dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING, permit a|b|c)
|
||||
dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING, SHELL-CODE-HANDLER)
|
||||
dnl
|
||||
dnl See docs/html/17_intro/configury.html#enable for documentation.
|
||||
dnl
|
||||
m4_define([LIBAT_ENABLE],[dnl
|
||||
m4_define([LIBFFI_ENABLE],[dnl
|
||||
m4_define([_g_switch],[--enable-$1])dnl
|
||||
m4_define([_g_help],[AC_HELP_STRING(_g_switch$3,[$4 @<:@default=$2@:>@])])dnl
|
||||
AC_ARG_ENABLE($1,_g_help,
|
||||
|
@ -146,7 +146,7 @@ dnl
|
|||
dnl The last will be a single integer, e.g., version 1.23.45.0.67.89 will
|
||||
dnl set libat_gnu_ld_version to 12345. Zeros cause problems.
|
||||
dnl
|
||||
AC_DEFUN([LIBAT_CHECK_LINKER_FEATURES], [
|
||||
AC_DEFUN([LIBFFI_CHECK_LINKER_FEATURES], [
|
||||
# If we're not using GNU ld, then there's no point in even trying these
|
||||
# tests. Check for that first. We should have already tested for gld
|
||||
# by now (in libtool), but require it now just to be safe...
|
||||
|
@ -178,7 +178,7 @@ AC_DEFUN([LIBAT_CHECK_LINKER_FEATURES], [
|
|||
fi
|
||||
changequote(,)
|
||||
ldver=`$LD --version 2>/dev/null |
|
||||
sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'`
|
||||
sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'`
|
||||
changequote([,])
|
||||
libat_gnu_ld_version=`echo $ldver | \
|
||||
$AWK -F. '{ if (NF<3) [$]3=0; print ([$]1*100+[$]2)*100+[$]3 }'`
|
||||
|
@ -248,7 +248,7 @@ dnl
|
|||
dnl The last will be a single integer, e.g., version 1.23.45.0.67.89 will
|
||||
dnl set libat_gnu_ld_version to 12345. Zeros cause problems.
|
||||
dnl
|
||||
AC_DEFUN([LIBAT_CHECK_LINKER_FEATURES], [
|
||||
AC_DEFUN([LIBFFI_CHECK_LINKER_FEATURES], [
|
||||
# If we're not using GNU ld, then there's no point in even trying these
|
||||
# tests. Check for that first. We should have already tested for gld
|
||||
# by now (in libtool), but require it now just to be safe...
|
||||
|
@ -278,9 +278,13 @@ AC_DEFUN([LIBAT_CHECK_LINKER_FEATURES], [
|
|||
if $LD --version 2>/dev/null | grep 'GNU gold'> /dev/null 2>&1; then
|
||||
libat_ld_is_gold=yes
|
||||
fi
|
||||
libat_ld_is_lld=no
|
||||
if $LD --version 2>/dev/null | grep 'LLD '> /dev/null 2>&1; then
|
||||
libat_ld_is_lld=yes
|
||||
fi
|
||||
changequote(,)
|
||||
ldver=`$LD --version 2>/dev/null |
|
||||
sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'`
|
||||
sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'`
|
||||
changequote([,])
|
||||
libat_gnu_ld_version=`echo $ldver | \
|
||||
$AWK -F. '{ if (NF<3) [$]3=0; print ([$]1*100+[$]2)*100+[$]3 }'`
|
||||
|
@ -341,20 +345,20 @@ dnl --enable-symvers=style adds a version script to the linker call when
|
|||
dnl creating the shared library. The choice of version script is
|
||||
dnl controlled by 'style'.
|
||||
dnl --disable-symvers does not.
|
||||
dnl + Usage: LIBAT_ENABLE_SYMVERS[(DEFAULT)]
|
||||
dnl + Usage: LIBFFI_ENABLE_SYMVERS[(DEFAULT)]
|
||||
dnl Where DEFAULT is either 'yes' or 'no'. Passing `yes' tries to
|
||||
dnl choose a default style based on linker characteristics. Passing
|
||||
dnl 'no' disables versioning.
|
||||
dnl
|
||||
AC_DEFUN([LIBAT_ENABLE_SYMVERS], [
|
||||
AC_DEFUN([LIBFFI_ENABLE_SYMVERS], [
|
||||
|
||||
LIBAT_ENABLE(symvers,yes,[=STYLE],
|
||||
LIBFFI_ENABLE(symvers,yes,[=STYLE],
|
||||
[enables symbol versioning of the shared library],
|
||||
[permit yes|no|gnu*|sun])
|
||||
|
||||
# If we never went through the LIBAT_CHECK_LINKER_FEATURES macro, then we
|
||||
# If we never went through the LIBFFI_CHECK_LINKER_FEATURES macro, then we
|
||||
# don't know enough about $LD to do tricks...
|
||||
AC_REQUIRE([LIBAT_CHECK_LINKER_FEATURES])
|
||||
AC_REQUIRE([LIBFFI_CHECK_LINKER_FEATURES])
|
||||
|
||||
# Turn a 'yes' into a suitable default.
|
||||
if test x$enable_symvers = xyes ; then
|
||||
|
@ -420,7 +424,7 @@ changequote([,])dnl
|
|||
fi
|
||||
|
||||
# For GNU ld, we need at least this version. The format is described in
|
||||
# LIBAT_CHECK_LINKER_FEATURES above.
|
||||
# LIBFFI_CHECK_LINKER_FEATURES above.
|
||||
libat_min_gnu_ld_version=21400
|
||||
# XXXXXXXXXXX libat_gnu_ld_version=21390
|
||||
|
||||
|
@ -432,6 +436,8 @@ if test $enable_symvers != no && test $libat_shared_libgcc = yes; then
|
|||
enable_symvers=gnu
|
||||
elif test $libat_ld_is_gold = yes ; then
|
||||
enable_symvers=gnu
|
||||
elif test $libat_ld_is_lld = yes ; then
|
||||
enable_symvers=gnu
|
||||
else
|
||||
# The right tools, the right setup, but too old. Fallbacks?
|
||||
AC_MSG_WARN(=== Linker version $libat_gnu_ld_version is too old for)
|
||||
|
@ -462,12 +468,12 @@ if test $enable_symvers != no && test $libat_shared_libgcc = yes; then
|
|||
fi
|
||||
fi
|
||||
if test $enable_symvers = gnu; then
|
||||
AC_DEFINE(LIBAT_GNU_SYMBOL_VERSIONING, 1,
|
||||
AC_DEFINE(LIBFFI_GNU_SYMBOL_VERSIONING, 1,
|
||||
[Define to 1 if GNU symbol versioning is used for libatomic.])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(LIBAT_BUILD_VERSIONED_SHLIB, test $enable_symvers != no)
|
||||
AM_CONDITIONAL(LIBAT_BUILD_VERSIONED_SHLIB_GNU, test $enable_symvers = gnu)
|
||||
AM_CONDITIONAL(LIBAT_BUILD_VERSIONED_SHLIB_SUN, test $enable_symvers = sun)
|
||||
AM_CONDITIONAL(LIBFFI_BUILD_VERSIONED_SHLIB, test $enable_symvers != no)
|
||||
AM_CONDITIONAL(LIBFFI_BUILD_VERSIONED_SHLIB_GNU, test $enable_symvers = gnu)
|
||||
AM_CONDITIONAL(LIBFFI_BUILD_VERSIONED_SHLIB_SUN, test $enable_symvers = sun)
|
||||
AC_MSG_NOTICE(versioning on shared library symbols is $enable_symvers)
|
||||
])
|
||||
|
|
1202
libffi/aclocal.m4
vendored
1202
libffi/aclocal.m4
vendored
File diff suppressed because it is too large
Load diff
19411
libffi/configure
vendored
19411
libffi/configure
vendored
File diff suppressed because it is too large
Load diff
|
@ -1,40 +1,22 @@
|
|||
dnl Process this with autoconf to create configure
|
||||
|
||||
AC_PREREQ(2.68)
|
||||
|
||||
AC_INIT([libffi], [3.99999], [http://github.com/atgreen/libffi/issues])
|
||||
AC_INIT([libffi], [3.4.2], [http://github.com/libffi/libffi/issues])
|
||||
AC_CONFIG_HEADERS([fficonfig.h])
|
||||
|
||||
AM_ENABLE_MULTILIB(, ..)
|
||||
|
||||
AC_CANONICAL_SYSTEM
|
||||
target_alias=${target_alias-$host_alias}
|
||||
|
||||
AM_INIT_AUTOMAKE([no-dist])
|
||||
case "${host}" in
|
||||
frv*-elf)
|
||||
LDFLAGS=`echo $LDFLAGS | sed "s/\-B[^ ]*libgloss\/frv\///"`\ -B`pwd`/../libgloss/frv/
|
||||
;;
|
||||
esac
|
||||
|
||||
# See if makeinfo has been installed and is modern enough
|
||||
# that we can use it.
|
||||
ACX_CHECK_PROG_VER([MAKEINFO], [makeinfo], [--version],
|
||||
[GNU texinfo.* \([0-9][0-9.]*\)],
|
||||
[4.[4-9]*|4.[1-9][0-9]*|[5-9]*|[1-9][0-9]*])
|
||||
AM_CONDITIONAL(BUILD_INFO, test $gcc_cv_prog_makeinfo_modern = "yes")
|
||||
AX_ENABLE_BUILDDIR
|
||||
|
||||
# We would like our source tree to be readonly. However when releases or
|
||||
# pre-releases are generated, the flex/bison generated files as well as the
|
||||
# various formats of manuals need to be included along with the rest of the
|
||||
# sources. Therefore we have --enable-generated-files-in-srcdir to do
|
||||
# just that.
|
||||
AC_MSG_CHECKING(generated-files-in-srcdir)
|
||||
AC_ARG_ENABLE(generated-files-in-srcdir,
|
||||
AS_HELP_STRING([--enable-generated-files-in-srcdir],
|
||||
[put copies of generated files in source dir intended for creating source tarballs for users without texinfo bison or flex]),
|
||||
[case "$enableval" in
|
||||
yes) enable_generated_files_in_srcdir=yes ;;
|
||||
no) enable_generated_files_in_srcdir=no ;;
|
||||
*) AC_MSG_ERROR([Unknown argument to enable/disable version-specific libs]);;
|
||||
esac],
|
||||
[enable_generated_files_in_srcdir=no])
|
||||
AC_MSG_RESULT($enable_generated_files_in_srcdir)
|
||||
AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes)
|
||||
AM_INIT_AUTOMAKE
|
||||
|
||||
# The same as in boehm-gc and libstdc++. Have to borrow it from there.
|
||||
# We must force CC to /not/ be precious variables; otherwise
|
||||
|
@ -57,19 +39,38 @@ AC_SUBST(CFLAGS)
|
|||
AM_PROG_AS
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_LIBTOOL
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_CHECK_TOOL(READELF, readelf)
|
||||
|
||||
# Test for 64-bit build.
|
||||
AC_CHECK_SIZEOF([size_t])
|
||||
|
||||
AX_COMPILER_VENDOR
|
||||
AX_CC_MAXOPT
|
||||
# The AX_CFLAGS_WARN_ALL macro doesn't currently work for sunpro
|
||||
# compiler.
|
||||
if test "$ax_cv_c_compiler_vendor" != "sun"; then
|
||||
AX_CFLAGS_WARN_ALL
|
||||
fi
|
||||
|
||||
if test "x$GCC" = "xyes"; then
|
||||
CFLAGS="$CFLAGS -fexceptions"
|
||||
fi
|
||||
|
||||
cat > local.exp <<EOF
|
||||
set CC_FOR_TARGET "$CC"
|
||||
set CXX_FOR_TARGET "$CXX"
|
||||
set compiler_vendor "$ax_cv_c_compiler_vendor"
|
||||
EOF
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_CHECK_HEADERS(sys/memfd.h)
|
||||
AC_CHECK_FUNCS([memfd_create])
|
||||
|
||||
AC_CHECK_HEADERS(sys/mman.h)
|
||||
AC_CHECK_FUNCS([mmap mkostemp])
|
||||
AC_CHECK_FUNCS([mmap mkostemp mkstemp])
|
||||
AC_FUNC_MMAP_BLACKLIST
|
||||
|
||||
dnl The -no-testsuite modules omit the test subdir.
|
||||
|
@ -181,6 +182,28 @@ case "$TARGET" in
|
|||
;;
|
||||
esac
|
||||
|
||||
AC_CACHE_CHECK([whether compiler supports pointer authentication],
|
||||
libffi_cv_as_ptrauth, [
|
||||
libffi_cv_as_ptrauth=unknown
|
||||
AC_TRY_COMPILE(,[
|
||||
#ifdef __clang__
|
||||
# if __has_feature(ptrauth_calls)
|
||||
# define HAVE_PTRAUTH 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTRAUTH
|
||||
# error Pointer authentication not supported
|
||||
#endif
|
||||
],
|
||||
[libffi_cv_as_ptrauth=yes],
|
||||
[libffi_cv_as_ptrauth=no])
|
||||
])
|
||||
if test "x$libffi_cv_as_ptrauth" = xyes; then
|
||||
AC_DEFINE(HAVE_PTRAUTH, 1,
|
||||
[Define if your compiler supports pointer authentication.])
|
||||
fi
|
||||
|
||||
# On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC.
|
||||
AC_ARG_ENABLE(pax_emutramp,
|
||||
[ --enable-pax_emutramp enable pax emulated trampolines, for we can't use PROT_EXEC],
|
||||
|
@ -189,15 +212,20 @@ AC_ARG_ENABLE(pax_emutramp,
|
|||
[Define this if you want to enable pax emulated trampolines])
|
||||
fi)
|
||||
|
||||
LT_SYS_SYMBOL_USCORE
|
||||
if test "x$sys_symbol_underscore" = xyes; then
|
||||
AC_DEFINE(SYMBOL_UNDERSCORE, 1, [Define if symbols are underscored.])
|
||||
fi
|
||||
|
||||
FFI_EXEC_TRAMPOLINE_TABLE=0
|
||||
case "$target" in
|
||||
*arm*-apple-darwin* | aarch64-apple-darwin*)
|
||||
*arm*-apple-* | aarch64-apple-*)
|
||||
FFI_EXEC_TRAMPOLINE_TABLE=1
|
||||
AC_DEFINE(FFI_EXEC_TRAMPOLINE_TABLE, 1,
|
||||
[Cannot use PROT_EXEC on this target, so, we revert to
|
||||
alternative means])
|
||||
;;
|
||||
*-apple-darwin1* | *-*-freebsd* | *-*-kfreebsd* | *-*-openbsd* | *-pc-solaris*)
|
||||
*-apple-* | *-*-freebsd* | *-*-kfreebsd* | *-*-openbsd* | *-pc-solaris* | *-linux-android*)
|
||||
AC_DEFINE(FFI_MMAP_EXEC_WRIT, 1,
|
||||
[Cannot use malloc on this target, so, we revert to
|
||||
alternative means])
|
||||
|
@ -238,19 +266,15 @@ EOF
|
|||
fi
|
||||
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AX_CHECK_COMPILE_FLAG(-fno-lto, libffi_cv_no_lto=-fno-lto)
|
||||
|
||||
AC_CACHE_CHECK([whether .eh_frame section should be read-only],
|
||||
libffi_cv_ro_eh_frame, [
|
||||
libffi_cv_ro_eh_frame=no
|
||||
libffi_cv_ro_eh_frame=yes
|
||||
echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c
|
||||
if $CC $CFLAGS -c -fpic -fexceptions -o conftest.o conftest.c > /dev/null 2>&1; then
|
||||
objdump -h conftest.o > conftest.dump 2>&1
|
||||
libffi_eh_frame_line=`grep -n eh_frame conftest.dump | cut -d: -f 1`
|
||||
if test "x$libffi_eh_frame_line" != "x"; then
|
||||
libffi_test_line=`expr $libffi_eh_frame_line + 1`p
|
||||
sed -n $libffi_test_line conftest.dump > conftest.line
|
||||
if grep READONLY conftest.line > /dev/null; then
|
||||
libffi_cv_ro_eh_frame=yes
|
||||
fi
|
||||
if $CC $CFLAGS -c -fpic -fexceptions $libffi_cv_no_lto -o conftest.o conftest.c > /dev/null 2>&1; then
|
||||
if $READELF -WS conftest.o | grep -q -n 'eh_frame .* WA'; then
|
||||
libffi_cv_ro_eh_frame=no
|
||||
fi
|
||||
fi
|
||||
rm -f conftest.*
|
||||
|
@ -270,7 +294,7 @@ if test "x$GCC" = "xyes"; then
|
|||
echo 'int __attribute__ ((visibility ("hidden"))) foo (void) { return 1 ; }' > conftest.c
|
||||
libffi_cv_hidden_visibility_attribute=no
|
||||
if AC_TRY_COMMAND(${CC-cc} -Werror -S conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then
|
||||
if grep '\.hidden.*foo' conftest.s >/dev/null; then
|
||||
if egrep '(\.hidden|\.private_extern).*foo' conftest.s >/dev/null; then
|
||||
libffi_cv_hidden_visibility_attribute=yes
|
||||
fi
|
||||
fi
|
||||
|
@ -282,10 +306,21 @@ if test "x$GCC" = "xyes"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(docs,
|
||||
AC_HELP_STRING([--disable-docs],
|
||||
[Disable building of docs (default: no)]),
|
||||
[enable_docs=no],
|
||||
[enable_docs=yes])
|
||||
AM_CONDITIONAL(BUILD_DOCS, [test x$enable_docs = xyes])
|
||||
|
||||
AH_BOTTOM([
|
||||
#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
|
||||
#ifdef LIBFFI_ASM
|
||||
#ifdef __APPLE__
|
||||
#define FFI_HIDDEN(name) .private_extern name
|
||||
#else
|
||||
#define FFI_HIDDEN(name) .hidden name
|
||||
#endif
|
||||
#else
|
||||
#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
|
||||
#endif
|
||||
|
@ -331,48 +366,56 @@ AC_ARG_ENABLE(raw-api,
|
|||
AC_DEFINE(FFI_NO_RAW_API, 1, [Define this if you do not want support for the raw API.])
|
||||
fi)
|
||||
|
||||
AC_ARG_ENABLE(exec-static-tramp,
|
||||
[ --disable-exec-static-tramp disable use of static exec trampolines (enabled by default)])
|
||||
|
||||
if test "$enable_exec_static_tramp" != no; then
|
||||
case "$target" in
|
||||
*-cygwin*)
|
||||
;;
|
||||
*arm*-*-linux-* | aarch64*-*-linux-* | i*86-*-linux-* | x86_64-*-linux-*)
|
||||
AC_DEFINE(FFI_EXEC_STATIC_TRAMP, 1,
|
||||
[Define this if you want statically defined trampolines])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(purify-safety,
|
||||
[ --enable-purify-safety purify-safe mode],
|
||||
if test "$enable_purify_safety" = "yes"; then
|
||||
AC_DEFINE(USING_PURIFY, 1, [Define this if you are using Purify and want to suppress spurious messages.])
|
||||
fi)
|
||||
|
||||
GCC_WITH_TOOLEXECLIBDIR
|
||||
|
||||
if test -n "$with_cross_host" &&
|
||||
test x"$with_cross_host" != x"no"; then
|
||||
toolexecdir='$(exec_prefix)/$(target_alias)'
|
||||
case ${with_toolexeclibdir} in
|
||||
no)
|
||||
toolexeclibdir='$(toolexecdir)/lib'
|
||||
;;
|
||||
*)
|
||||
toolexeclibdir=${with_toolexeclibdir}
|
||||
;;
|
||||
esac
|
||||
AC_ARG_ENABLE(multi-os-directory,
|
||||
[ --disable-multi-os-directory
|
||||
disable use of gcc --print-multi-os-directory to change the library installation directory])
|
||||
|
||||
# These variables are only ever used when we cross-build to X86_WIN32.
|
||||
# And we only support this with GCC, so...
|
||||
if test "x$GCC" = "xyes"; then
|
||||
if test -n "$with_cross_host" &&
|
||||
test x"$with_cross_host" != x"no"; then
|
||||
toolexecdir='${exec_prefix}'/'$(target_alias)'
|
||||
toolexeclibdir='${toolexecdir}'/lib
|
||||
else
|
||||
toolexecdir='${libdir}'/gcc-lib/'$(target_alias)'
|
||||
toolexeclibdir='${libdir}'
|
||||
fi
|
||||
if test x"$enable_multi_os_directory" != x"no"; then
|
||||
multi_os_directory=`$CC $CFLAGS -print-multi-os-directory`
|
||||
case $multi_os_directory in
|
||||
.) ;; # Avoid trailing /.
|
||||
../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;;
|
||||
esac
|
||||
fi
|
||||
AC_SUBST(toolexecdir)
|
||||
else
|
||||
toolexecdir='$(libdir)/gcc-lib/$(target_alias)'
|
||||
toolexeclibdir='$(libdir)'
|
||||
toolexeclibdir='${libdir}'
|
||||
fi
|
||||
multi_os_directory=`$CC -print-multi-os-directory`
|
||||
case $multi_os_directory in
|
||||
.) ;; # Avoid trailing /.
|
||||
*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;;
|
||||
esac
|
||||
AC_SUBST(toolexecdir)
|
||||
AC_SUBST(toolexeclibdir)
|
||||
|
||||
if test "${multilib}" = "yes"; then
|
||||
multilib_arg="--enable-multilib"
|
||||
else
|
||||
multilib_arg=
|
||||
fi
|
||||
|
||||
# Check linker support.
|
||||
LIBAT_ENABLE_SYMVERS
|
||||
|
||||
# Determine what GCC version number to use in filesystem paths.
|
||||
GCC_BASE_VER
|
||||
LIBFFI_ENABLE_SYMVERS
|
||||
|
||||
AC_CONFIG_COMMANDS(include, [test -d include || mkdir include])
|
||||
AC_CONFIG_COMMANDS(src, [
|
||||
|
@ -380,8 +423,10 @@ test -d src || mkdir src
|
|||
test -d src/$TARGETDIR || mkdir src/$TARGETDIR
|
||||
], [TARGETDIR="$TARGETDIR"])
|
||||
|
||||
AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETDIR/ffitarget.h)
|
||||
|
||||
AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc)
|
||||
AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile doc/Makefile libffi.pc)
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
# Copy this file instead of using AC_CONFIG_LINK in order to support
|
||||
# compiling with MSVC, which won't understand cygwin style symlinks.
|
||||
cp ${srcdir}/src/$TARGETDIR/ffitarget.h include/ffitarget.h
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
# THIS TABLE IS SORTED. KEEP IT THAT WAY.
|
||||
# Most of the time we can define all the variables all at once...
|
||||
case "${host}" in
|
||||
aarch64*-*-cygwin* | aarch64*-*-mingw* | aarch64*-*-win* )
|
||||
TARGET=ARM_WIN64; TARGETDIR=aarch64
|
||||
if test "${ax_cv_c_compiler_vendor}" = "microsoft"; then
|
||||
MSVC=1
|
||||
fi
|
||||
;;
|
||||
|
||||
aarch64*-*-*)
|
||||
TARGET=AARCH64; TARGETDIR=aarch64
|
||||
SOURCES="ffi.c sysv.S"
|
||||
|
@ -23,6 +30,13 @@ case "${host}" in
|
|||
SOURCES="ffi.c arcompact.S"
|
||||
;;
|
||||
|
||||
arm*-*-cygwin* | arm*-*-mingw* | arm*-*-win* )
|
||||
TARGET=ARM_WIN32; TARGETDIR=arm
|
||||
if test "${ax_cv_c_compiler_vendor}" = "microsoft"; then
|
||||
MSVC=1
|
||||
fi
|
||||
;;
|
||||
|
||||
arm*-*-*)
|
||||
TARGET=ARM; TARGETDIR=arm
|
||||
SOURCES="ffi.c sysv.S"
|
||||
|
@ -43,6 +57,11 @@ case "${host}" in
|
|||
SOURCES="ffi.c sysv.S"
|
||||
;;
|
||||
|
||||
csky-*-*)
|
||||
TARGET=CSKY; TARGETDIR=csky
|
||||
SOURCES="ffi.c sysv.S"
|
||||
;;
|
||||
|
||||
frv-*-*)
|
||||
TARGET=FRV; TARGETDIR=frv
|
||||
SOURCES="ffi.c eabi.S"
|
||||
|
@ -64,14 +83,17 @@ case "${host}" in
|
|||
TARGET=X86_FREEBSD; TARGETDIR=x86
|
||||
;;
|
||||
|
||||
i?86-win32* | i?86-*-cygwin* | i?86-*-mingw* | i?86-*-os2* | i?86-*-interix* \
|
||||
| x86_64-*-cygwin* | x86_64-*-mingw*)
|
||||
i?86-*-cygwin* | i?86-*-mingw* | i?86-*-win* | i?86-*-os2* | i?86-*-interix* \
|
||||
| x86_64-*-cygwin* | x86_64-*-mingw* | x86_64-*-win* )
|
||||
TARGETDIR=x86
|
||||
if test $ac_cv_sizeof_size_t = 4; then
|
||||
TARGET=X86_WIN32
|
||||
else
|
||||
TARGET=X86_WIN64
|
||||
fi
|
||||
if test "${ax_cv_c_compiler_vendor}" = "microsoft"; then
|
||||
MSVC=1
|
||||
fi
|
||||
# All mingw/cygwin/win32 builds require -no-undefined for sharedlib.
|
||||
# We must also check with_cross_host to decide if this is a native
|
||||
# or cross-build and select where to install dlls appropriately.
|
||||
|
@ -83,12 +105,12 @@ case "${host}" in
|
|||
fi
|
||||
;;
|
||||
|
||||
i?86-*-darwin* | x86_64-*-darwin*)
|
||||
i?86-*-darwin* | x86_64-*-darwin* | i?86-*-ios | x86_64-*-ios)
|
||||
TARGETDIR=x86
|
||||
if test $ac_cv_sizeof_size_t = 4; then
|
||||
TARGET=X86_DARWIN
|
||||
else
|
||||
TARGET=X86_64_DARWIN
|
||||
TARGET=X86_64
|
||||
fi
|
||||
;;
|
||||
|
||||
|
@ -97,11 +119,12 @@ case "${host}" in
|
|||
if test $ac_cv_sizeof_size_t = 4; then
|
||||
echo 'int foo (void) { return __x86_64__; }' > conftest.c
|
||||
if $CC $CFLAGS -Werror -S conftest.c -o conftest.s > /dev/null 2>&1; then
|
||||
TARGET=X86_64;
|
||||
TARGET_X32=yes
|
||||
TARGET=X86_64
|
||||
else
|
||||
TARGET=X86;
|
||||
fi
|
||||
rm -f conftest.*
|
||||
fi
|
||||
rm -f conftest.*
|
||||
else
|
||||
TARGET=X86_64;
|
||||
fi
|
||||
|
@ -112,6 +135,11 @@ case "${host}" in
|
|||
SOURCES="ffi.c unix.S"
|
||||
;;
|
||||
|
||||
kvx-*-*)
|
||||
TARGET=KVX; TARGETDIR=kvx
|
||||
SOURCES="ffi.c sysv.S"
|
||||
;;
|
||||
|
||||
m32r*-*-*)
|
||||
TARGET=M32R; TARGETDIR=m32r
|
||||
SOURCES="ffi.c sysv.S"
|
||||
|
@ -145,7 +173,7 @@ case "${host}" in
|
|||
mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
|
||||
TARGET=MIPS; TARGETDIR=mips
|
||||
;;
|
||||
mips*-*linux* | mips*-*-openbsd*)
|
||||
mips*-*linux* | mips*-*-openbsd* | mips*-*-freebsd*)
|
||||
# Support 128-bit long double for NewABI.
|
||||
HAVE_LONG_DOUBLE='defined(__mips64)'
|
||||
TARGET=MIPS; TARGETDIR=mips
|
||||
|
@ -156,7 +184,7 @@ case "${host}" in
|
|||
SOURCES="ffi.c sysv.S"
|
||||
;;
|
||||
|
||||
or1k*-linux*)
|
||||
or1k*-*-*)
|
||||
TARGET=OR1K; TARGETDIR=or1k
|
||||
SOURCES="ffi.c sysv.S"
|
||||
;;
|
||||
|
@ -168,6 +196,9 @@ case "${host}" in
|
|||
powerpc-*-amigaos*)
|
||||
TARGET=POWERPC; TARGETDIR=powerpc
|
||||
;;
|
||||
powerpc-*-eabi*)
|
||||
TARGET=POWERPC; TARGETDIR=powerpc
|
||||
;;
|
||||
powerpc-*-beos*)
|
||||
TARGET=POWERPC; TARGETDIR=powerpc
|
||||
;;
|
||||
|
@ -177,11 +208,15 @@ case "${host}" in
|
|||
powerpc-*-aix* | rs6000-*-aix*)
|
||||
TARGET=POWERPC_AIX; TARGETDIR=powerpc
|
||||
;;
|
||||
powerpc-*-freebsd* | powerpc-*-openbsd*)
|
||||
powerpc-*-freebsd* | powerpc-*-openbsd* | powerpc-*-netbsd*)
|
||||
TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
|
||||
HAVE_LONG_DOUBLE_VARIANT=1
|
||||
;;
|
||||
powerpc64-*-freebsd*)
|
||||
powerpcspe-*-freebsd*)
|
||||
TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
|
||||
CFLAGS="$CFLAGS -D__NO_FPRS__"
|
||||
;;
|
||||
powerpc64-*-freebsd* | powerpc64le-*-freebsd*)
|
||||
TARGET=POWERPC; TARGETDIR=powerpc
|
||||
;;
|
||||
powerpc*-*-rtems*)
|
||||
|
@ -230,6 +265,20 @@ esac
|
|||
|
||||
# ... but some of the cases above share configury.
|
||||
case "${TARGET}" in
|
||||
ARM_WIN32)
|
||||
if test "$MSVC" = 1; then
|
||||
SOURCES="ffi.c sysv_msvc_arm32.S"
|
||||
else
|
||||
SOURCES="ffi.c sysv.S"
|
||||
fi
|
||||
;;
|
||||
ARM_WIN64)
|
||||
if test "$MSVC" = 1; then
|
||||
SOURCES="ffi.c win64_armasm.S"
|
||||
else
|
||||
SOURCES="ffi.c sysv.S"
|
||||
fi
|
||||
;;
|
||||
MIPS)
|
||||
SOURCES="ffi.c o32.S n32.S"
|
||||
;;
|
||||
|
@ -246,20 +295,26 @@ case "${TARGET}" in
|
|||
POWERPC_FREEBSD)
|
||||
SOURCES="ffi.c ffi_sysv.c sysv.S ppc_closure.S"
|
||||
;;
|
||||
X86 | X86_FREEBSD | X86_WIN32)
|
||||
SOURCES="ffi.c sysv.S"
|
||||
X86 | X86_DARWIN | X86_FREEBSD | X86_WIN32)
|
||||
if test "$MSVC" = 1; then
|
||||
SOURCES="ffi.c sysv_intel.S"
|
||||
else
|
||||
SOURCES="ffi.c sysv.S"
|
||||
fi
|
||||
;;
|
||||
X86_64)
|
||||
SOURCES="ffi64.c unix64.S"
|
||||
if test x"$TARGET_X32" = xyes; then
|
||||
SOURCES="ffi64.c unix64.S"
|
||||
else
|
||||
SOURCES="ffi64.c unix64.S ffiw64.c win64.S"
|
||||
fi
|
||||
;;
|
||||
X86_WIN64)
|
||||
SOURCES="ffiw64.c win64.S"
|
||||
;;
|
||||
X86_DARWIN)
|
||||
SOURCES="darwin_c.c darwin.S"
|
||||
;;
|
||||
X86_64_DARWIN)
|
||||
SOURCES="darwin64_c.c darwin64.S"
|
||||
if test "$MSVC" = 1; then
|
||||
SOURCES="ffiw64.c win64_intel.S"
|
||||
else
|
||||
SOURCES="ffiw64.c win64.S"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
|
3
libffi/doc/Makefile.am
Normal file
3
libffi/doc/Makefile.am
Normal file
|
@ -0,0 +1,3 @@
|
|||
## Process this with automake to create Makefile.in
|
||||
|
||||
info_TEXINFOS = libffi.texi
|
|
@ -1,7 +1,8 @@
|
|||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename libffi.info
|
||||
@settitle libffi
|
||||
@include version.texi
|
||||
@settitle libffi: the portable foreign function interface library
|
||||
@setchapternewpage off
|
||||
@c %**end of header
|
||||
|
||||
|
@ -12,32 +13,43 @@
|
|||
@syncodeindex pg cp
|
||||
@syncodeindex tp cp
|
||||
|
||||
@include version.texi
|
||||
|
||||
@copying
|
||||
|
||||
This manual is for Libffi, a portable foreign-function interface
|
||||
This manual is for libffi, a portable foreign function interface
|
||||
library.
|
||||
|
||||
Copyright @copyright{} 2008, 2010, 2011 Red Hat, Inc.
|
||||
Copyright @copyright{} 2008--2019, 2021 Anthony Green and Red Hat, Inc.
|
||||
|
||||
@quotation
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version. A copy of the license is included in the
|
||||
section entitled ``GNU General Public License''.
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@end quotation
|
||||
@end copying
|
||||
|
||||
@dircategory Development
|
||||
@direntry
|
||||
* libffi: (libffi). Portable foreign-function interface library.
|
||||
* libffi: (libffi). Portable foreign function interface library.
|
||||
@end direntry
|
||||
|
||||
@titlepage
|
||||
@title Libffi
|
||||
@title libffi: a foreign function interface library
|
||||
@subtitle For Version @value{VERSION} of libffi
|
||||
@author Anthony Green
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
@insertcopying
|
||||
|
@ -53,6 +65,7 @@ section entitled ``GNU General Public License''.
|
|||
@menu
|
||||
* Introduction:: What is libffi?
|
||||
* Using libffi:: How to use libffi.
|
||||
* Memory Usage:: Where memory for closures comes from.
|
||||
* Missing Features:: Things libffi can't do.
|
||||
* Index:: Index.
|
||||
@end menu
|
||||
|
@ -107,6 +120,7 @@ values passed between the two languages.
|
|||
* Multiple ABIs:: Different passing styles on one platform.
|
||||
* The Closure API:: Writing a generic function.
|
||||
* Closure Example:: A closure example.
|
||||
* Thread Safety:: Thread safety.
|
||||
@end menu
|
||||
|
||||
|
||||
|
@ -152,16 +166,21 @@ If the function being called is variadic (varargs) then
|
|||
@code{ffi_prep_cif_var} must be used instead of @code{ffi_prep_cif}.
|
||||
|
||||
@findex ffi_prep_cif_var
|
||||
@defun ffi_status ffi_prep_cif_var (ffi_cif *@var{cif}, ffi_abi var{abi}, unsigned int @var{nfixedargs}, unsigned int var{ntotalargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
|
||||
@defun ffi_status ffi_prep_cif_var (ffi_cif *@var{cif}, ffi_abi @var{abi}, unsigned int @var{nfixedargs}, unsigned int @var{ntotalargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
|
||||
This initializes @var{cif} according to the given parameters for
|
||||
a call to a variadic function. In general it's operation is the
|
||||
a call to a variadic function. In general its operation is the
|
||||
same as for @code{ffi_prep_cif} except that:
|
||||
|
||||
@var{nfixedargs} is the number of fixed arguments, prior to any
|
||||
variadic arguments. It must be greater than zero.
|
||||
|
||||
@var{ntotalargs} the total number of arguments, including variadic
|
||||
and fixed arguments.
|
||||
and fixed arguments. @var{argtypes} must have this many elements.
|
||||
|
||||
@code{ffi_prep_cif_var} will return @code{FFI_BAD_ARGTYPE} if any of
|
||||
the variable argument types are @code{ffi_type_float} (promote to
|
||||
@code{ffi_type_double} first), or any integer type small than an int
|
||||
(promote to an int-sized type first).
|
||||
|
||||
Note that, different cif's must be prepped for calls to the same
|
||||
function when different numbers of arguments are passed.
|
||||
|
@ -172,6 +191,10 @@ Also note that a call to @code{ffi_prep_cif_var} with
|
|||
|
||||
@end defun
|
||||
|
||||
Note that the resulting @code{ffi_cif} holds pointers to all the
|
||||
@code{ffi_type} objects that were used during initialization. You
|
||||
must ensure that these type objects have a lifetime at least as long
|
||||
as that of the @code{ffi_cif}.
|
||||
|
||||
To call a function using an initialized @code{ffi_cif}, use the
|
||||
@code{ffi_call} function:
|
||||
|
@ -190,12 +213,29 @@ to ensure this. If @var{cif} declares that the function returns
|
|||
@code{void} (using @code{ffi_type_void}), then @var{rvalue} is
|
||||
ignored.
|
||||
|
||||
In most situations, @samp{libffi} will handle promotion according to
|
||||
the ABI. However, for historical reasons, there is a special case
|
||||
with return values that must be handled by your code. In particular,
|
||||
for integral (not @code{struct}) types that are narrower than the
|
||||
system register size, the return value will be widened by
|
||||
@samp{libffi}. @samp{libffi} provides a type, @code{ffi_arg}, that
|
||||
can be used as the return type. For example, if the CIF was defined
|
||||
with a return type of @code{char}, @samp{libffi} will try to store a
|
||||
full @code{ffi_arg} into the return value.
|
||||
|
||||
@var{avalues} is a vector of @code{void *} pointers that point to the
|
||||
memory locations holding the argument values for a call. If @var{cif}
|
||||
declares that the function has no arguments (i.e., @var{nargs} was 0),
|
||||
then @var{avalues} is ignored. Note that argument values may be
|
||||
modified by the callee (for instance, structs passed by value); the
|
||||
burden of copying pass-by-value arguments is placed on the caller.
|
||||
|
||||
Note that while the return value must be register-sized, arguments
|
||||
should exactly match their declared type. For example, if an argument
|
||||
is a @code{short}, then the entry in @var{avalues} should point to an
|
||||
object declared as @code{short}; but if the return type is
|
||||
@code{short}, then @var{rvalue} should point to an object declared as
|
||||
a larger type -- usually @code{ffi_arg}.
|
||||
@end defun
|
||||
|
||||
|
||||
|
@ -215,26 +255,26 @@ int main()
|
|||
void *values[1];
|
||||
char *s;
|
||||
ffi_arg rc;
|
||||
|
||||
/* Initialize the argument info vectors */
|
||||
|
||||
/* Initialize the argument info vectors */
|
||||
args[0] = &ffi_type_pointer;
|
||||
values[0] = &s;
|
||||
|
||||
|
||||
/* Initialize the cif */
|
||||
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
|
||||
&ffi_type_sint, args) == FFI_OK)
|
||||
@{
|
||||
s = "Hello World!";
|
||||
ffi_call(&cif, puts, &rc, values);
|
||||
/* rc now holds the result of the call to puts */
|
||||
|
||||
/* values holds a pointer to the function's arg, so to
|
||||
call puts() again all we need to do is change the
|
||||
|
||||
/* values holds a pointer to the function's arg, so to
|
||||
call puts() again all we need to do is change the
|
||||
value of s */
|
||||
s = "This is cool!";
|
||||
ffi_call(&cif, puts, &rc, values);
|
||||
@}
|
||||
|
||||
|
||||
return 0;
|
||||
@}
|
||||
@end example
|
||||
|
@ -246,6 +286,8 @@ int main()
|
|||
@menu
|
||||
* Primitive Types:: Built-in types.
|
||||
* Structures:: Structure types.
|
||||
* Size and Alignment:: Size and alignment of types.
|
||||
* Arrays Unions Enums:: Arrays, unions, and enumerations.
|
||||
* Type Example:: Structure type example.
|
||||
* Complex:: Complex types.
|
||||
* Complex Type Example:: Complex type example.
|
||||
|
@ -370,8 +412,7 @@ when passing to @code{ffi_prep_cif}.
|
|||
@node Structures
|
||||
@subsection Structures
|
||||
|
||||
Although @samp{libffi} has no special support for unions or
|
||||
bit-fields, it is perfectly happy passing structures back and forth.
|
||||
@samp{libffi} is perfectly happy passing structures back and forth.
|
||||
You must first describe the structure to @samp{libffi} by creating a
|
||||
new @code{ffi_type} object for it.
|
||||
|
||||
|
@ -391,9 +432,166 @@ For a structure, this should be set to @code{FFI_TYPE_STRUCT}.
|
|||
@item ffi_type **elements
|
||||
This is a @samp{NULL}-terminated array of pointers to @code{ffi_type}
|
||||
objects. There is one element per field of the struct.
|
||||
|
||||
Note that @samp{libffi} has no special support for bit-fields. You
|
||||
must manage these manually.
|
||||
@end table
|
||||
@end deftp
|
||||
|
||||
The @code{size} and @code{alignment} fields will be filled in by
|
||||
@code{ffi_prep_cif} or @code{ffi_prep_cif_var}, as needed.
|
||||
|
||||
@node Size and Alignment
|
||||
@subsection Size and Alignment
|
||||
|
||||
@code{libffi} will set the @code{size} and @code{alignment} fields of
|
||||
an @code{ffi_type} object for you. It does so using its knowledge of
|
||||
the ABI.
|
||||
|
||||
You might expect that you can simply read these fields for a type that
|
||||
has been laid out by @code{libffi}. However, there are some caveats.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
The size or alignment of some of the built-in types may vary depending
|
||||
on the chosen ABI.
|
||||
|
||||
@item
|
||||
The size and alignment of a new structure type will not be set by
|
||||
@code{libffi} until it has been passed to @code{ffi_prep_cif} or
|
||||
@code{ffi_get_struct_offsets}.
|
||||
|
||||
@item
|
||||
A structure type cannot be shared across ABIs. Instead each ABI needs
|
||||
its own copy of the structure type.
|
||||
@end itemize
|
||||
|
||||
So, before examining these fields, it is safest to pass the
|
||||
@code{ffi_type} object to @code{ffi_prep_cif} or
|
||||
@code{ffi_get_struct_offsets} first. This function will do all the
|
||||
needed setup.
|
||||
|
||||
@example
|
||||
ffi_type *desired_type;
|
||||
ffi_abi desired_abi;
|
||||
@dots{}
|
||||
ffi_cif cif;
|
||||
if (ffi_prep_cif (&cif, desired_abi, 0, desired_type, NULL) == FFI_OK)
|
||||
@{
|
||||
size_t size = desired_type->size;
|
||||
unsigned short alignment = desired_type->alignment;
|
||||
@}
|
||||
@end example
|
||||
|
||||
@code{libffi} also provides a way to get the offsets of the members of
|
||||
a structure.
|
||||
|
||||
@findex ffi_get_struct_offsets
|
||||
@defun ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets)
|
||||
Compute the offset of each element of the given structure type.
|
||||
@var{abi} is the ABI to use; this is needed because in some cases the
|
||||
layout depends on the ABI.
|
||||
|
||||
@var{offsets} is an out parameter. The caller is responsible for
|
||||
providing enough space for all the results to be written -- one
|
||||
element per element type in @var{struct_type}. If @var{offsets} is
|
||||
@code{NULL}, then the type will be laid out but not otherwise
|
||||
modified. This can be useful for accessing the type's size or layout,
|
||||
as mentioned above.
|
||||
|
||||
This function returns @code{FFI_OK} on success; @code{FFI_BAD_ABI} if
|
||||
@var{abi} is invalid; or @code{FFI_BAD_TYPEDEF} if @var{struct_type}
|
||||
is invalid in some way. Note that only @code{FFI_STRUCT} types are
|
||||
valid here.
|
||||
@end defun
|
||||
|
||||
@node Arrays Unions Enums
|
||||
@subsection Arrays, Unions, and Enumerations
|
||||
|
||||
@subsubsection Arrays
|
||||
|
||||
@samp{libffi} does not have direct support for arrays or unions.
|
||||
However, they can be emulated using structures.
|
||||
|
||||
To emulate an array, simply create an @code{ffi_type} using
|
||||
@code{FFI_TYPE_STRUCT} with as many members as there are elements in
|
||||
the array.
|
||||
|
||||
@example
|
||||
ffi_type array_type;
|
||||
ffi_type **elements
|
||||
int i;
|
||||
|
||||
elements = malloc ((n + 1) * sizeof (ffi_type *));
|
||||
for (i = 0; i < n; ++i)
|
||||
elements[i] = array_element_type;
|
||||
elements[n] = NULL;
|
||||
|
||||
array_type.size = array_type.alignment = 0;
|
||||
array_type.type = FFI_TYPE_STRUCT;
|
||||
array_type.elements = elements;
|
||||
@end example
|
||||
|
||||
Note that arrays cannot be passed or returned by value in C --
|
||||
structure types created like this should only be used to refer to
|
||||
members of real @code{FFI_TYPE_STRUCT} objects.
|
||||
|
||||
However, a phony array type like this will not cause any errors from
|
||||
@samp{libffi} if you use it as an argument or return type. This may
|
||||
be confusing.
|
||||
|
||||
@subsubsection Unions
|
||||
|
||||
A union can also be emulated using @code{FFI_TYPE_STRUCT}. In this
|
||||
case, however, you must make sure that the size and alignment match
|
||||
the real requirements of the union.
|
||||
|
||||
One simple way to do this is to ensue that each element type is laid
|
||||
out. Then, give the new structure type a single element; the size of
|
||||
the largest element; and the largest alignment seen as well.
|
||||
|
||||
This example uses the @code{ffi_prep_cif} trick to ensure that each
|
||||
element type is laid out.
|
||||
|
||||
@example
|
||||
ffi_abi desired_abi;
|
||||
ffi_type union_type;
|
||||
ffi_type **union_elements;
|
||||
|
||||
int i;
|
||||
ffi_type element_types[2];
|
||||
|
||||
element_types[1] = NULL;
|
||||
|
||||
union_type.size = union_type.alignment = 0;
|
||||
union_type.type = FFI_TYPE_STRUCT;
|
||||
union_type.elements = element_types;
|
||||
|
||||
for (i = 0; union_elements[i]; ++i)
|
||||
@{
|
||||
ffi_cif cif;
|
||||
if (ffi_prep_cif (&cif, desired_abi, 0, union_elements[i], NULL) == FFI_OK)
|
||||
@{
|
||||
if (union_elements[i]->size > union_type.size)
|
||||
@{
|
||||
union_type.size = union_elements[i];
|
||||
size = union_elements[i]->size;
|
||||
@}
|
||||
if (union_elements[i]->alignment > union_type.alignment)
|
||||
union_type.alignment = union_elements[i]->alignment;
|
||||
@}
|
||||
@}
|
||||
@end example
|
||||
|
||||
@subsubsection Enumerations
|
||||
|
||||
@code{libffi} does not have any special support for C @code{enum}s.
|
||||
Although any given @code{enum} is implemented using a specific
|
||||
underlying integral type, exactly which type will be used cannot be
|
||||
determined by @code{libffi} -- it may depend on the values in the
|
||||
enumeration or on compiler flags such as @option{-fshort-enums}.
|
||||
@xref{Structures unions enumerations and bit-fields implementation, , , gcc},
|
||||
for more information about how GCC handles enumerations.
|
||||
|
||||
@node Type Example
|
||||
@subsection Type Example
|
||||
|
@ -432,7 +630,7 @@ Here is the corresponding code to describe this struct to
|
|||
tm_type.size = tm_type.alignment = 0;
|
||||
tm_type.type = FFI_TYPE_STRUCT;
|
||||
tm_type.elements = &tm_type_elements;
|
||||
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
tm_type_elements[i] = &ffi_type_sint;
|
||||
|
||||
|
@ -630,30 +828,47 @@ the closure function:
|
|||
|
||||
@findex ffi_prep_closure_loc
|
||||
@defun ffi_status ffi_prep_closure_loc (ffi_closure *@var{closure}, ffi_cif *@var{cif}, void (*@var{fun}) (ffi_cif *@var{cif}, void *@var{ret}, void **@var{args}, void *@var{user_data}), void *@var{user_data}, void *@var{codeloc})
|
||||
Prepare a closure function.
|
||||
Prepare a closure function. The arguments to
|
||||
@code{ffi_prep_closure_loc} are:
|
||||
|
||||
@var{closure} is the address of a @code{ffi_closure} object; this is
|
||||
the writable address returned by @code{ffi_closure_alloc}.
|
||||
@table @var
|
||||
@item closure
|
||||
The address of a @code{ffi_closure} object; this is the writable
|
||||
address returned by @code{ffi_closure_alloc}.
|
||||
|
||||
@var{cif} is the @code{ffi_cif} describing the function parameters.
|
||||
@item cif
|
||||
The @code{ffi_cif} describing the function parameters. Note that this
|
||||
object, and the types to which it refers, must be kept alive until the
|
||||
closure itself is freed.
|
||||
|
||||
@var{user_data} is an arbitrary datum that is passed, uninterpreted,
|
||||
to your closure function.
|
||||
@item user_data
|
||||
An arbitrary datum that is passed, uninterpreted, to your closure
|
||||
function.
|
||||
|
||||
@var{codeloc} is the executable address returned by
|
||||
@code{ffi_closure_alloc}.
|
||||
@item codeloc
|
||||
The executable address returned by @code{ffi_closure_alloc}.
|
||||
|
||||
@item fun
|
||||
The function which will be called when the closure is invoked. It is
|
||||
called with the arguments:
|
||||
|
||||
@var{fun} is the function which will be called when the closure is
|
||||
invoked. It is called with the arguments:
|
||||
@table @var
|
||||
@item cif
|
||||
The @code{ffi_cif} passed to @code{ffi_prep_closure_loc}.
|
||||
|
||||
@item ret
|
||||
A pointer to the memory used for the function's return value.
|
||||
@var{fun} must fill this, unless the function is declared as returning
|
||||
@code{void}.
|
||||
@c FIXME: is this NULL for void-returning functions?
|
||||
|
||||
If the function is declared as returning @code{void}, then this value
|
||||
is garbage and should not be used.
|
||||
|
||||
Otherwise, @var{fun} must fill the object to which this points,
|
||||
following the same special promotion behavior as @code{ffi_call}.
|
||||
That is, in most cases, @var{ret} points to an object of exactly the
|
||||
size of the type specified when @var{cif} was constructed. However,
|
||||
integral types narrower than the system register size are widened. In
|
||||
these cases your program may assume that @var{ret} points to an
|
||||
@code{ffi_arg} object.
|
||||
|
||||
@item args
|
||||
A vector of pointers to memory holding the arguments to the function.
|
||||
|
@ -662,10 +877,10 @@ A vector of pointers to memory holding the arguments to the function.
|
|||
The same @var{user_data} that was passed to
|
||||
@code{ffi_prep_closure_loc}.
|
||||
@end table
|
||||
@end table
|
||||
|
||||
@code{ffi_prep_closure_loc} will return @code{FFI_OK} if everything
|
||||
went ok, and something else on error.
|
||||
@c FIXME: what?
|
||||
went ok, and one of the other @code{ffi_status} values on error.
|
||||
|
||||
After calling @code{ffi_prep_closure_loc}, you can cast @var{codeloc}
|
||||
to the appropriate pointer-to-function type.
|
||||
|
@ -678,7 +893,7 @@ writable and executable addresses.
|
|||
@node Closure Example
|
||||
@section Closure Example
|
||||
|
||||
A trivial example that creates a new @code{puts} by binding
|
||||
A trivial example that creates a new @code{puts} by binding
|
||||
@code{fputs} with @code{stdout}.
|
||||
|
||||
@example
|
||||
|
@ -733,6 +948,77 @@ int main()
|
|||
|
||||
@end example
|
||||
|
||||
@node Thread Safety
|
||||
@section Thread Safety
|
||||
|
||||
@code{libffi} is not completely thread-safe. However, many parts are,
|
||||
and if you follow some simple rules, you can use it safely in a
|
||||
multi-threaded program.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
@code{ffi_prep_cif} may modify the @code{ffi_type} objects passed to
|
||||
it. It is best to ensure that only a single thread prepares a given
|
||||
@code{ffi_cif} at a time.
|
||||
|
||||
@item
|
||||
On some platforms, @code{ffi_prep_cif} may modify the size and
|
||||
alignment of some types, depending on the chosen ABI. On these
|
||||
platforms, if you switch between ABIs, you must ensure that there is
|
||||
only one call to @code{ffi_prep_cif} at a time.
|
||||
|
||||
Currently the only affected platform is PowerPC and the only affected
|
||||
type is @code{long double}.
|
||||
@end itemize
|
||||
|
||||
@node Memory Usage
|
||||
@chapter Memory Usage
|
||||
|
||||
Note that memory allocated by @code{ffi_closure_alloc} and freed by
|
||||
@code{ffi_closure_free} does not come from the same general pool of
|
||||
memory that @code{malloc} and @code{free} use. To accomodate security
|
||||
settings, @samp{libffi} may aquire memory, for example, by mapping
|
||||
temporary files into multiple places in the address space (once to
|
||||
write out the closure, a second to execute it). The search follows
|
||||
this list, using the first that works:
|
||||
|
||||
@itemize @bullet
|
||||
|
||||
@item
|
||||
A anonymous mapping (i.e. not file-backed)
|
||||
|
||||
@item
|
||||
@code{memfd_create()}, if the kernel supports it.
|
||||
|
||||
@item
|
||||
A file created in the directory referenced by the environment variable
|
||||
@code{LIBFFI_TMPDIR}.
|
||||
|
||||
@item
|
||||
Likewise for the environment variable @code{TMPDIR}.
|
||||
|
||||
@item
|
||||
A file created in @code{/tmp}.
|
||||
|
||||
@item
|
||||
A file created in @code{/var/tmp}.
|
||||
|
||||
@item
|
||||
A file created in @code{/dev/shm}.
|
||||
|
||||
@item
|
||||
A file created in the user's home directory (@code{$HOME}).
|
||||
|
||||
@item
|
||||
A file created in any directory listed in @code{/etc/mtab}.
|
||||
|
||||
@item
|
||||
A file created in any directory listed in @code{/proc/mounts}.
|
||||
|
||||
@end itemize
|
||||
|
||||
If security settings prohibit using any of these for closures,
|
||||
@code{ffi_closure_alloc} will fail.
|
||||
|
||||
@node Missing Features
|
||||
@chapter Missing Features
|
||||
|
@ -749,13 +1035,11 @@ There is no support for bit fields in structures.
|
|||
|
||||
@item
|
||||
The ``raw'' API is undocumented.
|
||||
@c argument promotion?
|
||||
@c unions?
|
||||
@c anything else?
|
||||
@end itemize
|
||||
|
||||
Note that variadic support is very new and tested on a relatively
|
||||
small number of platforms.
|
||||
@item
|
||||
The Go API is undocumented.
|
||||
@end itemize
|
||||
|
||||
@node Index
|
||||
@unnumbered Index
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@set UPDATED 8 November 2014
|
||||
@set UPDATED-MONTH November 2014
|
||||
@set EDITION 3.2.1
|
||||
@set VERSION 3.2.1
|
||||
@set UPDATED 27 June 2021
|
||||
@set UPDATED-MONTH June 2021
|
||||
@set EDITION 3.4.2
|
||||
@set VERSION 3.4.2
|
||||
|
|
|
@ -1,208 +0,0 @@
|
|||
/* fficonfig.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Define to the flags needed for the .section .eh_frame directive. */
|
||||
#undef EH_FRAME_FLAGS
|
||||
|
||||
/* Define this if you want extra debugging. */
|
||||
#undef FFI_DEBUG
|
||||
|
||||
/* Cannot use PROT_EXEC on this target, so, we revert to alternative means */
|
||||
#undef FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
/* Define this if you want to enable pax emulated trampolines */
|
||||
#undef FFI_MMAP_EXEC_EMUTRAMP_PAX
|
||||
|
||||
/* Cannot use malloc on this target, so, we revert to alternative means */
|
||||
#undef FFI_MMAP_EXEC_WRIT
|
||||
|
||||
/* Define this if you do not want support for the raw API. */
|
||||
#undef FFI_NO_RAW_API
|
||||
|
||||
/* Define this if you do not want support for aggregate types. */
|
||||
#undef FFI_NO_STRUCTS
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define if your assembler supports .cfi_* directives. */
|
||||
#undef HAVE_AS_CFI_PSEUDO_OP
|
||||
|
||||
/* Define if your assembler supports .register. */
|
||||
#undef HAVE_AS_REGISTER_PSEUDO_OP
|
||||
|
||||
/* Define if the compiler uses zarch features. */
|
||||
#undef HAVE_AS_S390_ZARCH
|
||||
|
||||
/* Define if your assembler and linker support unaligned PC relative relocs.
|
||||
*/
|
||||
#undef HAVE_AS_SPARC_UA_PCREL
|
||||
|
||||
/* Define if your assembler supports unwind section type. */
|
||||
#undef HAVE_AS_X86_64_UNWIND_SECTION_TYPE
|
||||
|
||||
/* Define if your assembler supports PC relative relocs. */
|
||||
#undef HAVE_AS_X86_PCREL
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define if __attribute__((visibility("hidden"))) is supported. */
|
||||
#undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define if you have the long double type and it is bigger than a double */
|
||||
#undef HAVE_LONG_DOUBLE
|
||||
|
||||
/* Define if you support more than one size of the long double type */
|
||||
#undef HAVE_LONG_DOUBLE_VARIANT
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#undef HAVE_MEMCPY
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mkostemp' function. */
|
||||
#undef HAVE_MKOSTEMP
|
||||
|
||||
/* Define to 1 if you have the `mmap' function. */
|
||||
#undef HAVE_MMAP
|
||||
|
||||
/* Define if mmap with MAP_ANON(YMOUS) works. */
|
||||
#undef HAVE_MMAP_ANON
|
||||
|
||||
/* Define if mmap of /dev/zero works. */
|
||||
#undef HAVE_MMAP_DEV_ZERO
|
||||
|
||||
/* Define if read-only mmap of a plain file works. */
|
||||
#undef HAVE_MMAP_FILE
|
||||
|
||||
/* Define if .eh_frame sections should be read-only. */
|
||||
#undef HAVE_RO_EH_FRAME
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#undef HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if GNU symbol versioning is used for libatomic. */
|
||||
#undef LIBAT_GNU_SYMBOL_VERSIONING
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* The size of `double', as computed by sizeof. */
|
||||
#undef SIZEOF_DOUBLE
|
||||
|
||||
/* The size of `long double', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG_DOUBLE
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#undef SIZEOF_SIZE_T
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define this if you are using Purify and want to suppress spurious messages.
|
||||
*/
|
||||
#undef USING_PURIFY
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
|
||||
#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
|
||||
#ifdef LIBFFI_ASM
|
||||
#define FFI_HIDDEN(name) .hidden name
|
||||
#else
|
||||
#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
|
||||
#endif
|
||||
#else
|
||||
#ifdef LIBFFI_ASM
|
||||
#define FFI_HIDDEN(name)
|
||||
#else
|
||||
#define FFI_HIDDEN
|
||||
#endif
|
||||
#endif
|
||||
|
143
libffi/generate-darwin-source-and-headers.py
Normal file → Executable file
143
libffi/generate-darwin-source-and-headers.py
Normal file → Executable file
|
@ -6,59 +6,73 @@ import collections
|
|||
import glob
|
||||
import argparse
|
||||
|
||||
|
||||
class Platform(object):
|
||||
pass
|
||||
|
||||
|
||||
class simulator_platform(Platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphonesimulator'
|
||||
arch = 'i386'
|
||||
triple = 'i386-apple-darwin11'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
prefix = "#ifdef __i386__\n\n"
|
||||
suffix = "\n\n#endif"
|
||||
src_dir = 'x86'
|
||||
src_files = ['darwin.S', 'win32.S', 'ffi.c']
|
||||
src_files = ['sysv.S', 'ffi.c', 'internal.h']
|
||||
|
||||
|
||||
class simulator64_platform(Platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphonesimulator'
|
||||
arch = 'x86_64'
|
||||
triple = 'x86_64-apple-darwin13'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
prefix = "#ifdef __x86_64__\n\n"
|
||||
suffix = "\n\n#endif"
|
||||
src_dir = 'x86'
|
||||
src_files = ['darwin64.S', 'ffi64.c']
|
||||
src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
|
||||
|
||||
|
||||
class device_platform(Platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphoneos'
|
||||
arch = 'armv7'
|
||||
triple = 'arm-apple-darwin11'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
prefix = "#ifdef __arm__\n\n"
|
||||
suffix = "\n\n#endif"
|
||||
src_dir = 'arm'
|
||||
src_files = ['sysv.S', 'trampoline.S', 'ffi.c']
|
||||
src_files = ['sysv.S', 'ffi.c', 'internal.h']
|
||||
|
||||
|
||||
class device64_platform(Platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphoneos'
|
||||
arch = 'arm64'
|
||||
triple = 'aarch64-apple-darwin13'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
prefix = "#ifdef __arm64__\n\n"
|
||||
suffix = "\n\n#endif"
|
||||
src_dir = 'aarch64'
|
||||
src_files = ['sysv.S', 'ffi.c']
|
||||
src_files = ['sysv.S', 'ffi.c', 'internal.h']
|
||||
|
||||
|
||||
class ios_simulator_platform(simulator_platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphonesimulator'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
|
||||
class ios_simulator64_platform(simulator64_platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphonesimulator'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
|
||||
class ios_device_platform(device_platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphoneos'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
|
||||
class ios_device64_platform(device64_platform):
|
||||
directory = 'darwin_ios'
|
||||
sdk = 'iphoneos'
|
||||
version_min = '-miphoneos-version-min=7.0'
|
||||
|
||||
|
||||
class desktop32_platform(Platform):
|
||||
|
@ -68,7 +82,7 @@ class desktop32_platform(Platform):
|
|||
triple = 'i386-apple-darwin10'
|
||||
version_min = '-mmacosx-version-min=10.6'
|
||||
src_dir = 'x86'
|
||||
src_files = ['darwin.S', 'win32.S', 'ffi.c']
|
||||
src_files = ['sysv.S', 'ffi.c', 'internal.h']
|
||||
|
||||
prefix = "#ifdef __i386__\n\n"
|
||||
suffix = "\n\n#endif"
|
||||
|
@ -84,16 +98,39 @@ class desktop64_platform(Platform):
|
|||
prefix = "#ifdef __x86_64__\n\n"
|
||||
suffix = "\n\n#endif"
|
||||
src_dir = 'x86'
|
||||
src_files = ['darwin64.S', 'ffi64.c']
|
||||
src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
|
||||
|
||||
|
||||
class tvos_simulator64_platform(simulator64_platform):
|
||||
directory = 'darwin_tvos'
|
||||
sdk = 'appletvsimulator'
|
||||
version_min = '-mtvos-version-min=9.0'
|
||||
|
||||
|
||||
class tvos_device64_platform(device64_platform):
|
||||
directory = 'darwin_tvos'
|
||||
sdk = 'appletvos'
|
||||
version_min = '-mtvos-version-min=9.0'
|
||||
|
||||
|
||||
class watchos_simulator_platform(simulator_platform):
|
||||
directory = 'darwin_watchos'
|
||||
sdk = 'watchsimulator'
|
||||
version_min = '-mwatchos-version-min=4.0'
|
||||
|
||||
|
||||
class watchos_device_platform(device_platform):
|
||||
directory = 'darwin_watchos'
|
||||
sdk = 'watchos'
|
||||
arch = 'armv7k'
|
||||
version_min = '-mwatchos-version-min=4.0'
|
||||
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc: # Python >2.5
|
||||
if exc.errno == errno.EEXIST:
|
||||
pass
|
||||
else:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
|
||||
|
@ -102,8 +139,11 @@ def move_file(src_dir, dst_dir, filename, file_suffix=None, prefix='', suffix=''
|
|||
out_filename = filename
|
||||
|
||||
if file_suffix:
|
||||
split_name = os.path.splitext(filename)
|
||||
out_filename = "%s_%s%s" % (split_name[0], file_suffix, split_name[1])
|
||||
if filename in ['internal64.h', 'asmnames.h', 'internal.h']:
|
||||
out_filename = filename
|
||||
else:
|
||||
split_name = os.path.splitext(filename)
|
||||
out_filename = "%s_%s%s" % (split_name[0], file_suffix, split_name[1])
|
||||
|
||||
with open(os.path.join(src_dir, filename)) as in_file:
|
||||
with open(os.path.join(dst_dir, out_filename), 'w') as out_file:
|
||||
|
@ -142,7 +182,7 @@ def build_target(platform, platform_headers):
|
|||
mkdir_p(build_dir)
|
||||
env = dict(CC=xcrun_cmd('clang'),
|
||||
LD=xcrun_cmd('ld'),
|
||||
CFLAGS='%s' % (platform.version_min))
|
||||
CFLAGS='%s -fembed-bitcode' % (platform.version_min))
|
||||
working_dir = os.getcwd()
|
||||
try:
|
||||
os.chdir(build_dir)
|
||||
|
@ -162,39 +202,47 @@ def build_target(platform, platform_headers):
|
|||
platform_headers[filename].add((platform.prefix, platform.arch, platform.suffix))
|
||||
|
||||
|
||||
def make_tramp():
|
||||
with open('src/arm/trampoline.S', 'w') as tramp_out:
|
||||
p = subprocess.Popen(['bash', 'src/arm/gentramp.sh'], stdout=tramp_out)
|
||||
p.wait()
|
||||
|
||||
|
||||
def generate_source_and_headers(generate_osx=True, generate_ios=True):
|
||||
def generate_source_and_headers(
|
||||
generate_osx=True,
|
||||
generate_ios=True,
|
||||
generate_tvos=True,
|
||||
generate_watchos=True,
|
||||
):
|
||||
copy_files('src', 'darwin_common/src', pattern='*.c')
|
||||
copy_files('include', 'darwin_common/include', pattern='*.h')
|
||||
|
||||
if generate_ios:
|
||||
make_tramp()
|
||||
copy_src_platform_files(simulator_platform)
|
||||
copy_src_platform_files(simulator64_platform)
|
||||
copy_src_platform_files(device_platform)
|
||||
copy_src_platform_files(device64_platform)
|
||||
copy_src_platform_files(ios_simulator_platform)
|
||||
copy_src_platform_files(ios_simulator64_platform)
|
||||
copy_src_platform_files(ios_device_platform)
|
||||
copy_src_platform_files(ios_device64_platform)
|
||||
if generate_osx:
|
||||
copy_src_platform_files(desktop32_platform)
|
||||
copy_src_platform_files(desktop64_platform)
|
||||
if generate_tvos:
|
||||
copy_src_platform_files(tvos_simulator64_platform)
|
||||
copy_src_platform_files(tvos_device64_platform)
|
||||
if generate_watchos:
|
||||
copy_src_platform_files(watchos_simulator_platform)
|
||||
copy_src_platform_files(watchos_device_platform)
|
||||
|
||||
platform_headers = collections.defaultdict(set)
|
||||
|
||||
if generate_ios:
|
||||
build_target(simulator_platform, platform_headers)
|
||||
build_target(simulator64_platform, platform_headers)
|
||||
build_target(device_platform, platform_headers)
|
||||
build_target(device64_platform, platform_headers)
|
||||
build_target(ios_simulator_platform, platform_headers)
|
||||
build_target(ios_simulator64_platform, platform_headers)
|
||||
build_target(ios_device_platform, platform_headers)
|
||||
build_target(ios_device64_platform, platform_headers)
|
||||
if generate_osx:
|
||||
build_target(desktop32_platform, platform_headers)
|
||||
build_target(desktop64_platform, platform_headers)
|
||||
if generate_tvos:
|
||||
build_target(tvos_simulator64_platform, platform_headers)
|
||||
build_target(tvos_device64_platform, platform_headers)
|
||||
if generate_watchos:
|
||||
build_target(watchos_simulator_platform, platform_headers)
|
||||
build_target(watchos_device_platform, platform_headers)
|
||||
|
||||
mkdir_p('darwin_common/include')
|
||||
for header_name, tag_tuples in platform_headers.iteritems():
|
||||
for header_name, tag_tuples in platform_headers.items():
|
||||
basename, suffix = os.path.splitext(header_name)
|
||||
with open(os.path.join('darwin_common/include', header_name), 'w') as header:
|
||||
for tag_tuple in tag_tuples:
|
||||
|
@ -204,6 +252,13 @@ if __name__ == '__main__':
|
|||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--only-ios', action='store_true', default=False)
|
||||
parser.add_argument('--only-osx', action='store_true', default=False)
|
||||
parser.add_argument('--only-tvos', action='store_true', default=False)
|
||||
parser.add_argument('--only-watchos', action='store_true', default=False)
|
||||
args = parser.parse_args()
|
||||
|
||||
generate_source_and_headers(generate_osx=not args.only_ios, generate_ios=not args.only_osx)
|
||||
generate_source_and_headers(
|
||||
generate_osx=not args.only_ios and not args.only_tvos and not args.only_watchos,
|
||||
generate_ios=not args.only_osx and not args.only_tvos and not args.only_watchos,
|
||||
generate_tvos=not args.only_ios and not args.only_osx and not args.only_watchos,
|
||||
generate_watchos=not args.only_ios and not args.only_osx and not args.only_tvos,
|
||||
)
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
AUTOMAKE_OPTIONS=foreign
|
||||
|
||||
DISTCLEANFILES=ffitarget.h
|
||||
noinst_HEADERS=ffi_common.h ffi_cfi.h
|
||||
noinst_HEADERS=ffi_common.h ffi_cfi.h tramp.h
|
||||
EXTRA_DIST=ffi.h.in
|
||||
|
||||
# Where generated headers like ffitarget.h get installed.
|
||||
gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
|
||||
toollibffidir := $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
|
||||
|
||||
toollibffi_HEADERS = ffi.h ffitarget.h
|
||||
nodist_include_HEADERS = ffi.h ffitarget.h
|
||||
|
|
|
@ -1,565 +0,0 @@
|
|||
# Makefile.in generated by automake 1.15.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2017 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
subdir = include
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
||||
$(top_srcdir)/../config/asmcfi.m4 \
|
||||
$(top_srcdir)/../config/depstand.m4 \
|
||||
$(top_srcdir)/../config/lead-dot.m4 \
|
||||
$(top_srcdir)/../config/multi.m4 \
|
||||
$(top_srcdir)/../config/override.m4 \
|
||||
$(top_srcdir)/../config/toolexeclibdir.m4 \
|
||||
$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
|
||||
$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
|
||||
$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
|
||||
$(toollibffi_HEADERS)
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
|
||||
CONFIG_HEADER = $(top_builddir)/fficonfig.h
|
||||
CONFIG_CLEAN_FILES = ffi.h ffitarget.h
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(toollibffidir)"
|
||||
HEADERS = $(noinst_HEADERS) $(toollibffi_HEADERS)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
ACLOCAL = @ACLOCAL@
|
||||
ALLOCA = @ALLOCA@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AM_LTLDFLAGS = @AM_LTLDFLAGS@
|
||||
AM_RUNTESTFLAGS = @AM_RUNTESTFLAGS@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FFI_EXEC_TRAMPOLINE_TABLE = @FFI_EXEC_TRAMPOLINE_TABLE@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
HAVE_LONG_DOUBLE = @HAVE_LONG_DOUBLE@
|
||||
HAVE_LONG_DOUBLE_VARIANT = @HAVE_LONG_DOUBLE_VARIANT@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OPT_LDFLAGS = @OPT_LDFLAGS@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SECTION_LDFLAGS = @SECTION_LDFLAGS@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
TARGET = @TARGET@
|
||||
TARGETDIR = @TARGETDIR@
|
||||
TARGET_OBJ = @TARGET_OBJ@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
get_gcc_base_ver = @get_gcc_base_ver@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
multi_basedir = @multi_basedir@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
toolexecdir = @toolexecdir@
|
||||
toolexeclibdir = @toolexeclibdir@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
DISTCLEANFILES = ffitarget.h
|
||||
noinst_HEADERS = ffi_common.h ffi_cfi.h
|
||||
EXTRA_DIST = ffi.h.in
|
||||
|
||||
# Where generated headers like ffitarget.h get installed.
|
||||
gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
|
||||
toollibffidir := $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
|
||||
toollibffi_HEADERS = ffi.h ffitarget.h
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign include/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
ffi.h: $(top_builddir)/config.status $(srcdir)/ffi.h.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-toollibffiHEADERS: $(toollibffi_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(toollibffi_HEADERS)'; test -n "$(toollibffidir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(toollibffidir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(toollibffidir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(toollibffidir)'"; \
|
||||
$(INSTALL_HEADER) $$files "$(DESTDIR)$(toollibffidir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-toollibffiHEADERS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(toollibffi_HEADERS)'; test -n "$(toollibffidir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(toollibffidir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(HEADERS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(toollibffidir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-toollibffiHEADERS
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-toollibffiHEADERS
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool cscopelist-am ctags ctags-am distclean \
|
||||
distclean-generic distclean-libtool distclean-tags dvi dvi-am \
|
||||
html html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip \
|
||||
install-toollibffiHEADERS installcheck installcheck-am \
|
||||
installdirs maintainer-clean maintainer-clean-generic \
|
||||
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
|
||||
ps ps-am tags tags-am uninstall uninstall-am \
|
||||
uninstall-toollibffiHEADERS
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
|
@ -1,6 +1,7 @@
|
|||
/* -----------------------------------------------------------------*-C-*-
|
||||
libffi @VERSION@ - Copyright (c) 2011, 2014 Anthony Green
|
||||
- Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
|
||||
libffi @VERSION@
|
||||
- Copyright (c) 2011, 2014, 2019, 2021 Anthony Green
|
||||
- Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
@ -25,23 +26,14 @@
|
|||
----------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
The basic API is described in the README file.
|
||||
Most of the API is documented in doc/libffi.texi.
|
||||
|
||||
The raw API is designed to bypass some of the argument packing
|
||||
and unpacking on architectures for which it can be avoided.
|
||||
The raw API is designed to bypass some of the argument packing and
|
||||
unpacking on architectures for which it can be avoided. Routines
|
||||
are provided to emulate the raw API if the underlying platform
|
||||
doesn't allow faster implementation.
|
||||
|
||||
The closure API allows interpreted functions to be packaged up
|
||||
inside a C function pointer, so that they can be called as C functions,
|
||||
with no understanding on the client side that they are interpreted.
|
||||
It can also be used in other cases in which it is necessary to package
|
||||
up a user specified parameter and a function pointer as a single
|
||||
function pointer.
|
||||
|
||||
The closure API must be implemented in order to get its functionality,
|
||||
e.g. for use by gij. Routines are provided to emulate the raw API
|
||||
if the underlying platform doesn't allow faster implementation.
|
||||
|
||||
More details on the raw and cloure API can be found in:
|
||||
More details on the raw API can be found in:
|
||||
|
||||
http://gcc.gnu.org/ml/java/1999-q3/msg00138.html
|
||||
|
||||
|
@ -106,8 +98,8 @@ extern "C" {
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/* The closure code assumes that this works on pointers, i.e. a size_t */
|
||||
/* can hold a pointer. */
|
||||
/* The closure code assumes that this works on pointers, i.e. a size_t
|
||||
can hold a pointer. */
|
||||
|
||||
typedef struct _ffi_type
|
||||
{
|
||||
|
@ -117,6 +109,32 @@ typedef struct _ffi_type
|
|||
struct _ffi_type **elements;
|
||||
} ffi_type;
|
||||
|
||||
/* Need minimal decorations for DLLs to work on Windows. GCC has
|
||||
autoimport and autoexport. Always mark externally visible symbols
|
||||
as dllimport for MSVC clients, even if it means an extra indirection
|
||||
when using the static version of the library.
|
||||
Besides, as a workaround, they can define FFI_BUILDING if they
|
||||
*know* they are going to link with the static library. */
|
||||
#if defined _MSC_VER
|
||||
# if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
|
||||
# define FFI_API __declspec(dllexport)
|
||||
# elif !defined FFI_BUILDING /* Importing libffi.DLL */
|
||||
# define FFI_API __declspec(dllimport)
|
||||
# else /* Building/linking static library */
|
||||
# define FFI_API
|
||||
# endif
|
||||
#else
|
||||
# define FFI_API
|
||||
#endif
|
||||
|
||||
/* The externally visible type declarations also need the MSVC DLL
|
||||
decorations, or they will not be exported from the object file. */
|
||||
#if defined LIBFFI_HIDE_BASIC_TYPES
|
||||
# define FFI_EXTERN FFI_API
|
||||
#else
|
||||
# define FFI_EXTERN extern FFI_API
|
||||
#endif
|
||||
|
||||
#ifndef LIBFFI_HIDE_BASIC_TYPES
|
||||
#if SCHAR_MAX == 127
|
||||
# define ffi_type_uchar ffi_type_uint8
|
||||
|
@ -166,21 +184,7 @@ typedef struct _ffi_type
|
|||
#error "long size not supported"
|
||||
#endif
|
||||
|
||||
/* Need minimal decorations for DLLs to works on Windows. */
|
||||
/* GCC has autoimport and autoexport. Rely on Libtool to */
|
||||
/* help MSVC export from a DLL, but always declare data */
|
||||
/* to be imported for MSVC clients. This costs an extra */
|
||||
/* indirection for MSVC clients using the static version */
|
||||
/* of the library, but don't worry about that. Besides, */
|
||||
/* as a workaround, they can define FFI_BUILDING if they */
|
||||
/* *know* they are going to link with the static library. */
|
||||
#if defined _MSC_VER && !defined FFI_BUILDING
|
||||
#define FFI_EXTERN extern __declspec(dllimport)
|
||||
#else
|
||||
#define FFI_EXTERN extern
|
||||
#endif
|
||||
|
||||
/* These are defined in types.c */
|
||||
/* These are defined in types.c. */
|
||||
FFI_EXTERN ffi_type ffi_type_void;
|
||||
FFI_EXTERN ffi_type ffi_type_uint8;
|
||||
FFI_EXTERN ffi_type ffi_type_sint8;
|
||||
|
@ -214,11 +218,10 @@ FFI_EXTERN ffi_type ffi_type_complex_longdouble;
|
|||
typedef enum {
|
||||
FFI_OK = 0,
|
||||
FFI_BAD_TYPEDEF,
|
||||
FFI_BAD_ABI
|
||||
FFI_BAD_ABI,
|
||||
FFI_BAD_ARGTYPE
|
||||
} ffi_status;
|
||||
|
||||
typedef unsigned FFI_TYPE;
|
||||
|
||||
typedef struct {
|
||||
ffi_abi abi;
|
||||
unsigned nargs;
|
||||
|
@ -231,20 +234,6 @@ typedef struct {
|
|||
#endif
|
||||
} ffi_cif;
|
||||
|
||||
#if @HAVE_LONG_DOUBLE_VARIANT@
|
||||
/* Used to adjust size/alignment of ffi types. */
|
||||
void ffi_prep_types (ffi_abi abi);
|
||||
#endif
|
||||
|
||||
/* Used internally, but overridden by some architectures */
|
||||
ffi_status ffi_prep_cif_core(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int isvariadic,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
|
||||
/* ---- Definitions for the raw API -------------------------------------- */
|
||||
|
||||
#ifndef FFI_SIZEOF_ARG
|
||||
|
@ -282,27 +271,34 @@ typedef ffi_raw ffi_java_raw;
|
|||
#endif
|
||||
|
||||
|
||||
FFI_API
|
||||
void ffi_raw_call (ffi_cif *cif,
|
||||
void (*fn)(void),
|
||||
void *rvalue,
|
||||
ffi_raw *avalue);
|
||||
|
||||
void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
|
||||
void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
|
||||
size_t ffi_raw_size (ffi_cif *cif);
|
||||
FFI_API void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
|
||||
FFI_API void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
|
||||
FFI_API size_t ffi_raw_size (ffi_cif *cif);
|
||||
|
||||
/* This is analogous to the raw API, except it uses Java parameter */
|
||||
/* packing, even on 64-bit machines. I.e. on 64-bit machines */
|
||||
/* longs and doubles are followed by an empty 64-bit word. */
|
||||
/* This is analogous to the raw API, except it uses Java parameter
|
||||
packing, even on 64-bit machines. I.e. on 64-bit machines longs
|
||||
and doubles are followed by an empty 64-bit word. */
|
||||
|
||||
#if !FFI_NATIVE_RAW_API
|
||||
FFI_API
|
||||
void ffi_java_raw_call (ffi_cif *cif,
|
||||
void (*fn)(void),
|
||||
void *rvalue,
|
||||
ffi_java_raw *avalue);
|
||||
ffi_java_raw *avalue) __attribute__((deprecated));
|
||||
#endif
|
||||
|
||||
void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw);
|
||||
void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args);
|
||||
size_t ffi_java_raw_size (ffi_cif *cif);
|
||||
FFI_API
|
||||
void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) __attribute__((deprecated));
|
||||
FFI_API
|
||||
void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) __attribute__((deprecated));
|
||||
FFI_API
|
||||
size_t ffi_java_raw_size (ffi_cif *cif) __attribute__((deprecated));
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
|
@ -316,30 +312,50 @@ typedef struct {
|
|||
void *trampoline_table;
|
||||
void *trampoline_table_entry;
|
||||
#else
|
||||
char tramp[FFI_TRAMPOLINE_SIZE];
|
||||
union {
|
||||
char tramp[FFI_TRAMPOLINE_SIZE];
|
||||
void *ftramp;
|
||||
};
|
||||
#endif
|
||||
ffi_cif *cif;
|
||||
void (*fun)(ffi_cif*,void*,void**,void*);
|
||||
void *user_data;
|
||||
} ffi_closure
|
||||
#ifdef __GNUC__
|
||||
} ffi_closure __attribute__((aligned (8)));
|
||||
#else
|
||||
} ffi_closure;
|
||||
__attribute__((aligned (8)))
|
||||
#endif
|
||||
;
|
||||
|
||||
#ifndef __GNUC__
|
||||
# ifdef __sgi
|
||||
# pragma pack 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void *ffi_closure_alloc (size_t size, void **code);
|
||||
void ffi_closure_free (void *);
|
||||
FFI_API void *ffi_closure_alloc (size_t size, void **code);
|
||||
FFI_API void ffi_closure_free (void *);
|
||||
|
||||
ffi_status
|
||||
#if defined(PA_LINUX) || defined(PA_HPUX)
|
||||
#define FFI_CLOSURE_PTR(X) ((void *)((unsigned int)(X) | 2))
|
||||
#define FFI_RESTORE_PTR(X) ((void *)((unsigned int)(X) & ~3))
|
||||
#else
|
||||
#define FFI_CLOSURE_PTR(X) (X)
|
||||
#define FFI_RESTORE_PTR(X) (X)
|
||||
#endif
|
||||
|
||||
FFI_API ffi_status
|
||||
ffi_prep_closure (ffi_closure*,
|
||||
ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data);
|
||||
void *user_data)
|
||||
#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 405)
|
||||
__attribute__((deprecated ("use ffi_prep_closure_loc instead")))
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 3
|
||||
__attribute__((deprecated))
|
||||
#endif
|
||||
;
|
||||
|
||||
ffi_status
|
||||
FFI_API ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure*,
|
||||
ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
|
@ -360,9 +376,9 @@ typedef struct {
|
|||
|
||||
#if !FFI_NATIVE_RAW_API
|
||||
|
||||
/* if this is enabled, then a raw closure has the same layout
|
||||
as a regular closure. We use this to install an intermediate
|
||||
handler to do the transaltion, void** -> ffi_raw*. */
|
||||
/* If this is enabled, then a raw closure has the same layout
|
||||
as a regular closure. We use this to install an intermediate
|
||||
handler to do the transaltion, void** -> ffi_raw*. */
|
||||
|
||||
void (*translate_args)(ffi_cif*,void*,void**,void*);
|
||||
void *this_closure;
|
||||
|
@ -386,9 +402,9 @@ typedef struct {
|
|||
|
||||
#if !FFI_NATIVE_RAW_API
|
||||
|
||||
/* if this is enabled, then a raw closure has the same layout
|
||||
as a regular closure. We use this to install an intermediate
|
||||
handler to do the transaltion, void** -> ffi_raw*. */
|
||||
/* If this is enabled, then a raw closure has the same layout
|
||||
as a regular closure. We use this to install an intermediate
|
||||
handler to do the translation, void** -> ffi_raw*. */
|
||||
|
||||
void (*translate_args)(ffi_cif*,void*,void**,void*);
|
||||
void *this_closure;
|
||||
|
@ -400,31 +416,33 @@ typedef struct {
|
|||
|
||||
} ffi_java_raw_closure;
|
||||
|
||||
ffi_status
|
||||
FFI_API ffi_status
|
||||
ffi_prep_raw_closure (ffi_raw_closure*,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
||||
void *user_data);
|
||||
|
||||
ffi_status
|
||||
FFI_API ffi_status
|
||||
ffi_prep_raw_closure_loc (ffi_raw_closure*,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
||||
void *user_data,
|
||||
void *codeloc);
|
||||
|
||||
ffi_status
|
||||
#if !FFI_NATIVE_RAW_API
|
||||
FFI_API ffi_status
|
||||
ffi_prep_java_raw_closure (ffi_java_raw_closure*,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
|
||||
void *user_data);
|
||||
void *user_data) __attribute__((deprecated));
|
||||
|
||||
ffi_status
|
||||
FFI_API ffi_status
|
||||
ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
|
||||
void *user_data,
|
||||
void *codeloc);
|
||||
void *codeloc) __attribute__((deprecated));
|
||||
#endif
|
||||
|
||||
#endif /* FFI_CLOSURES */
|
||||
|
||||
|
@ -436,22 +454,24 @@ typedef struct {
|
|||
void (*fun)(ffi_cif*,void*,void**,void*);
|
||||
} ffi_go_closure;
|
||||
|
||||
ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
|
||||
FFI_API ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*));
|
||||
|
||||
void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
FFI_API void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure);
|
||||
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
|
||||
/* ---- Public interface definition -------------------------------------- */
|
||||
|
||||
FFI_API
|
||||
ffi_status ffi_prep_cif(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
|
||||
FFI_API
|
||||
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nfixedargs,
|
||||
|
@ -459,12 +479,17 @@ ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
|||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
|
||||
FFI_API
|
||||
void ffi_call(ffi_cif *cif,
|
||||
void (*fn)(void),
|
||||
void *rvalue,
|
||||
void **avalue);
|
||||
|
||||
/* Useful for eliminating compiler warnings */
|
||||
FFI_API
|
||||
ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
|
||||
size_t *offsets);
|
||||
|
||||
/* Useful for eliminating compiler warnings. */
|
||||
#define FFI_FN(f) ((void (*)(void))f)
|
||||
|
||||
/* ---- Definitions shared with assembly code ---------------------------- */
|
||||
|
@ -472,18 +497,18 @@ void ffi_call(ffi_cif *cif,
|
|||
#endif
|
||||
|
||||
/* If these change, update src/mips/ffitarget.h. */
|
||||
#define FFI_TYPE_VOID 0
|
||||
#define FFI_TYPE_VOID 0
|
||||
#define FFI_TYPE_INT 1
|
||||
#define FFI_TYPE_FLOAT 2
|
||||
#define FFI_TYPE_FLOAT 2
|
||||
#define FFI_TYPE_DOUBLE 3
|
||||
#if @HAVE_LONG_DOUBLE@
|
||||
#define FFI_TYPE_LONGDOUBLE 4
|
||||
#else
|
||||
#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
|
||||
#endif
|
||||
#define FFI_TYPE_UINT8 5
|
||||
#define FFI_TYPE_UINT8 5
|
||||
#define FFI_TYPE_SINT8 6
|
||||
#define FFI_TYPE_UINT16 7
|
||||
#define FFI_TYPE_UINT16 7
|
||||
#define FFI_TYPE_SINT16 8
|
||||
#define FFI_TYPE_UINT32 9
|
||||
#define FFI_TYPE_SINT32 10
|
||||
|
@ -493,14 +518,8 @@ void ffi_call(ffi_cif *cif,
|
|||
#define FFI_TYPE_POINTER 14
|
||||
#define FFI_TYPE_COMPLEX 15
|
||||
|
||||
/* This should always refer to the last type code (for sanity checks) */
|
||||
/* ??? Ideally, anyway. There are assembly files that still depend
|
||||
on this not including COMPLEX. */
|
||||
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
# define FFI_TYPE_LAST FFI_TYPE_COMPLEX
|
||||
#else
|
||||
# define FFI_TYPE_LAST FFI_TYPE_POINTER
|
||||
#endif
|
||||
/* This should always refer to the last type code (for sanity checks). */
|
||||
#define FFI_TYPE_LAST FFI_TYPE_COMPLEX
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -2,6 +2,27 @@
|
|||
ffi_cfi.h - Copyright (c) 2014 Red Hat, Inc.
|
||||
|
||||
Conditionally assemble cfi directives. Only necessary for building libffi.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the ``Software''), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef FFI_CFI_H
|
||||
|
|
|
@ -5,6 +5,27 @@
|
|||
|
||||
Common internal definitions and macros. Only necessary for building
|
||||
libffi.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the ``Software''), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef FFI_COMMON_H
|
||||
|
@ -74,14 +95,39 @@ void ffi_type_test(ffi_type *a, char *file, int line);
|
|||
#define FFI_ASSERT_VALID_TYPE(x)
|
||||
#endif
|
||||
|
||||
#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
|
||||
#define ALIGN_DOWN(v, a) (((size_t) (v)) & -a)
|
||||
/* v cast to size_t and aligned up to a multiple of a */
|
||||
#define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
|
||||
/* v cast to size_t and aligned down to a multiple of a */
|
||||
#define FFI_ALIGN_DOWN(v, a) (((size_t) (v)) & -a)
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
|
||||
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
|
||||
unsigned int nfixedargs, unsigned int ntotalargs);
|
||||
|
||||
|
||||
#if HAVE_LONG_DOUBLE_VARIANT
|
||||
/* Used to adjust size/alignment of ffi types. */
|
||||
void ffi_prep_types (ffi_abi abi);
|
||||
#endif
|
||||
|
||||
/* Used internally, but overridden by some architectures */
|
||||
ffi_status ffi_prep_cif_core(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int isvariadic,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
|
||||
/* Translate a data pointer to a code pointer. Needed for closures on
|
||||
some targets. */
|
||||
void *ffi_data_to_code_pointer (void *data) FFI_HIDDEN;
|
||||
|
||||
/* The arch code calls this to determine if a given closure has a
|
||||
static trampoline. */
|
||||
int ffi_tramp_is_present (void *closure) FFI_HIDDEN;
|
||||
|
||||
/* Extended cif, used in callback from assembly routine */
|
||||
typedef struct
|
||||
{
|
||||
|
|
45
libffi/include/tramp.h
Normal file
45
libffi/include/tramp.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi_tramp.h - Copyright (C) 2021 Microsoft, Inc.
|
||||
|
||||
Static trampoline definitions.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the ``Software''), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef FFI_TRAMP_H
|
||||
#define FFI_TRAMP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ffi_tramp_is_supported(void);
|
||||
void *ffi_tramp_alloc (int flags);
|
||||
void ffi_tramp_set_parms (void *tramp, void *data, void *code);
|
||||
void *ffi_tramp_get_addr (void *tramp);
|
||||
void ffi_tramp_free (void *tramp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FFI_TRAMP_H */
|
|
@ -3,7 +3,10 @@
|
|||
#include <fficonfig.h>
|
||||
#include <ffitarget.h>
|
||||
|
||||
LIBFFI_BASE_7.0 {
|
||||
/* These version numbers correspond to the libtool-version abi numbers,
|
||||
not to the libffi release numbers. */
|
||||
|
||||
LIBFFI_BASE_8.0 {
|
||||
global:
|
||||
/* Exported data variables. */
|
||||
ffi_type_void;
|
||||
|
@ -35,28 +38,23 @@ LIBFFI_BASE_7.0 {
|
|||
ffi_java_raw_to_ptrarray;
|
||||
ffi_java_raw_size;
|
||||
|
||||
/* Functions in the ffi.h header, but not exported.
|
||||
These are listed here for documentation purposes only.
|
||||
ffi_prep_types
|
||||
ffi_prep_cif_core
|
||||
*/
|
||||
|
||||
ffi_get_struct_offsets;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
LIBFFI_COMPLEX_7.0 {
|
||||
LIBFFI_COMPLEX_8.0 {
|
||||
global:
|
||||
/* Exported data variables. */
|
||||
ffi_type_complex_float;
|
||||
ffi_type_complex_double;
|
||||
ffi_type_complex_longdouble;
|
||||
} LIBFFI_BASE_7.0;
|
||||
} LIBFFI_BASE_8.0;
|
||||
#endif
|
||||
|
||||
#if FFI_CLOSURES
|
||||
LIBFFI_CLOSURE_7.0 {
|
||||
LIBFFI_CLOSURE_8.0 {
|
||||
global:
|
||||
ffi_closure_alloc;
|
||||
ffi_closure_free;
|
||||
|
@ -66,13 +64,13 @@ LIBFFI_CLOSURE_7.0 {
|
|||
ffi_prep_raw_closure_loc;
|
||||
ffi_prep_java_raw_closure;
|
||||
ffi_prep_java_raw_closure_loc;
|
||||
} LIBFFI_BASE_7.0;
|
||||
} LIBFFI_BASE_8.0;
|
||||
#endif
|
||||
|
||||
#if FFI_GO_CLOSURES
|
||||
LIBFFI_GO_CLOSURE_7.0 {
|
||||
LIBFFI_GO_CLOSURE_8.0 {
|
||||
global:
|
||||
ffi_call_go;
|
||||
ffi_prep_go_closure;
|
||||
} LIBFFI_CLOSURE_7.0;
|
||||
} LIBFFI_CLOSURE_8.0;
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@ prefix=@prefix@
|
|||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
toolexeclibdir=@toolexeclibdir@
|
||||
includedir=${libdir}/@PACKAGE_NAME@-@PACKAGE_VERSION@/include
|
||||
includedir=@includedir@
|
||||
|
||||
Name: @PACKAGE_NAME@
|
||||
Description: Library supporting Foreign Function Interfaces
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
43B5D3F81D35473200D1E1FD /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */; };
|
||||
43B5D3FA1D3547CE00D1E1FD /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */; };
|
||||
43E9A5C81D352C1500926A8F /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43E9A5C61D352C1500926A8F /* unix64_x86_64.S */; };
|
||||
DBFA714A187F1D8600A76262 /* ffi.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
|
||||
DBFA714B187F1D8600A76262 /* ffi_common.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA713F187F1D8600A76262 /* ffi_common.h */; };
|
||||
DBFA714C187F1D8600A76262 /* fficonfig.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7140187F1D8600A76262 /* fficonfig.h */; };
|
||||
|
@ -23,36 +26,110 @@
|
|||
DBFA7178187F1D9B00A76262 /* sysv_arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716D187F1D9B00A76262 /* sysv_arm64.S */; };
|
||||
DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716F187F1D9B00A76262 /* ffi_armv7.c */; };
|
||||
DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7170187F1D9B00A76262 /* sysv_armv7.S */; };
|
||||
DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */; };
|
||||
DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */; };
|
||||
DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7174187F1D9B00A76262 /* darwin_i386.S */; };
|
||||
DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */; };
|
||||
DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7176187F1D9B00A76262 /* ffi_i386.c */; };
|
||||
DBFA718E187F1DA100A76262 /* ffi_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7182187F1DA100A76262 /* ffi_i386.h */; };
|
||||
DBFA718F187F1DA100A76262 /* ffi_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7183187F1DA100A76262 /* ffi_x86_64.h */; };
|
||||
DBFA7190187F1DA100A76262 /* fficonfig_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7184187F1DA100A76262 /* fficonfig_i386.h */; };
|
||||
DBFA7191187F1DA100A76262 /* fficonfig_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */; };
|
||||
DBFA7192187F1DA100A76262 /* ffitarget_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7186187F1DA100A76262 /* ffitarget_i386.h */; };
|
||||
DBFA7193187F1DA100A76262 /* ffitarget_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */; };
|
||||
DBFA7194187F1DA100A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */; };
|
||||
DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718B187F1DA100A76262 /* darwin_i386.S */; };
|
||||
DBFA7194187F1DA100A76262 /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* unix64_x86_64.S */; };
|
||||
DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */; };
|
||||
DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718D187F1DA100A76262 /* ffi_i386.c */; };
|
||||
FDB52FB31F6144FA00AA92E6 /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43E9A5C61D352C1500926A8F /* unix64_x86_64.S */; };
|
||||
FDB52FB51F6144FA00AA92E6 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */; };
|
||||
FDB52FB61F6144FA00AA92E6 /* ffi_armv7.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716F187F1D9B00A76262 /* ffi_armv7.c */; };
|
||||
FDB52FB71F6144FA00AA92E6 /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7143187F1D8600A76262 /* closures.c */; };
|
||||
FDB52FB81F6144FA00AA92E6 /* sysv_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7170187F1D9B00A76262 /* sysv_armv7.S */; };
|
||||
FDB52FB91F6144FA00AA92E6 /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */; };
|
||||
FDB52FBA1F6144FA00AA92E6 /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7147187F1D8600A76262 /* prep_cif.c */; };
|
||||
FDB52FBC1F6144FA00AA92E6 /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7148187F1D8600A76262 /* raw_api.c */; };
|
||||
FDB52FBD1F6144FA00AA92E6 /* sysv_arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716D187F1D9B00A76262 /* sysv_arm64.S */; };
|
||||
FDB52FBE1F6144FA00AA92E6 /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7149187F1D8600A76262 /* types.c */; };
|
||||
FDB52FBF1F6144FA00AA92E6 /* ffi_arm64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716C187F1D9B00A76262 /* ffi_arm64.c */; };
|
||||
FDB52FC01F6144FA00AA92E6 /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */; };
|
||||
FDB52FD01F614A8B00AA92E6 /* ffi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
|
||||
FDB52FD11F614AA700AA92E6 /* ffi_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA715E187F1D9B00A76262 /* ffi_arm64.h */; };
|
||||
FDB52FD21F614AAB00AA92E6 /* ffi_armv7.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA715F187F1D9B00A76262 /* ffi_armv7.h */; };
|
||||
FDB52FD41F614AB500AA92E6 /* ffi_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */; };
|
||||
FDB52FD51F614AE200AA92E6 /* ffi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
|
||||
FDB52FD61F614AEA00AA92E6 /* ffi_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA715E187F1D9B00A76262 /* ffi_arm64.h */; };
|
||||
FDB52FD71F614AED00AA92E6 /* ffi_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */; };
|
||||
FDB52FD81F614B8700AA92E6 /* ffitarget.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7141187F1D8600A76262 /* ffitarget.h */; };
|
||||
FDB52FD91F614B8E00AA92E6 /* ffitarget_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */; };
|
||||
FDB52FDA1F614B9300AA92E6 /* ffitarget_armv7.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7167187F1D9B00A76262 /* ffitarget_armv7.h */; };
|
||||
FDB52FDD1F614BA900AA92E6 /* ffitarget_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */; };
|
||||
FDB52FDE1F6155E300AA92E6 /* ffitarget.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7141187F1D8600A76262 /* ffitarget.h */; };
|
||||
FDB52FDF1F6155EA00AA92E6 /* ffitarget_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */; };
|
||||
FDB52FE01F6155EF00AA92E6 /* ffitarget_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */; };
|
||||
FDB52FE21F6156FA00AA92E6 /* ffi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
|
||||
FDB52FE31F61571A00AA92E6 /* ffi_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7183187F1DA100A76262 /* ffi_x86_64.h */; };
|
||||
FDB52FE41F61571D00AA92E6 /* ffitarget.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7141187F1D8600A76262 /* ffitarget.h */; };
|
||||
FDB52FE61F61573100AA92E6 /* ffitarget_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */; };
|
||||
FDDB2F411F5D66E200EF414E /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */; };
|
||||
FDDB2F461F5D691E00EF414E /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F441F5D68C900EF414E /* win64_x86_64.S */; };
|
||||
FDDB2F4A1F5D846400EF414E /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */; };
|
||||
FDDB2F4C1F5D846400EF414E /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7147187F1D8600A76262 /* prep_cif.c */; };
|
||||
FDDB2F4E1F5D846400EF414E /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */; };
|
||||
FDDB2F4F1F5D846400EF414E /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7149187F1D8600A76262 /* types.c */; };
|
||||
FDDB2F501F5D846400EF414E /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7148187F1D8600A76262 /* raw_api.c */; };
|
||||
FDDB2F511F5D846400EF414E /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7143187F1D8600A76262 /* closures.c */; };
|
||||
FDDB2F521F5D846400EF414E /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* unix64_x86_64.S */; };
|
||||
FDDB2F531F5D846400EF414E /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F441F5D68C900EF414E /* win64_x86_64.S */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
DB13B1641849DF1E0010F42D /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 8;
|
||||
buildActionMask = 12;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
FDB52FD01F614A8B00AA92E6 /* ffi.h in CopyFiles */,
|
||||
FDB52FD11F614AA700AA92E6 /* ffi_arm64.h in CopyFiles */,
|
||||
FDB52FD21F614AAB00AA92E6 /* ffi_armv7.h in CopyFiles */,
|
||||
FDB52FD41F614AB500AA92E6 /* ffi_x86_64.h in CopyFiles */,
|
||||
FDB52FD81F614B8700AA92E6 /* ffitarget.h in CopyFiles */,
|
||||
FDB52FD91F614B8E00AA92E6 /* ffitarget_arm64.h in CopyFiles */,
|
||||
FDB52FDA1F614B9300AA92E6 /* ffitarget_armv7.h in CopyFiles */,
|
||||
FDB52FDD1F614BA900AA92E6 /* ffitarget_x86_64.h in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FDB52FC11F6144FA00AA92E6 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 12;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
FDB52FD51F614AE200AA92E6 /* ffi.h in CopyFiles */,
|
||||
FDB52FD61F614AEA00AA92E6 /* ffi_arm64.h in CopyFiles */,
|
||||
FDB52FD71F614AED00AA92E6 /* ffi_x86_64.h in CopyFiles */,
|
||||
FDB52FDE1F6155E300AA92E6 /* ffitarget.h in CopyFiles */,
|
||||
FDB52FDF1F6155EA00AA92E6 /* ffitarget_arm64.h in CopyFiles */,
|
||||
FDB52FE01F6155EF00AA92E6 /* ffitarget_x86_64.h in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FDB52FE11F6156E000AA92E6 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
FDB52FE21F6156FA00AA92E6 /* ffi.h in CopyFiles */,
|
||||
FDB52FE31F61571A00AA92E6 /* ffi_x86_64.h in CopyFiles */,
|
||||
FDB52FE41F61571D00AA92E6 /* ffitarget.h in CopyFiles */,
|
||||
FDB52FE61F61573100AA92E6 /* ffitarget_x86_64.h in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffiw64_x86_64.c; sourceTree = "<group>"; };
|
||||
43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = win64_x86_64.S; sourceTree = "<group>"; };
|
||||
43E9A5C61D352C1500926A8F /* unix64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = unix64_x86_64.S; sourceTree = "<group>"; };
|
||||
43E9A5DA1D35373600926A8F /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
|
||||
43E9A5DB1D35374400926A8F /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
|
||||
43E9A5DC1D35375400926A8F /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
|
||||
43E9A5DD1D35375400926A8F /* internal64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal64.h; sourceTree = "<group>"; };
|
||||
DB13B1661849DF1E0010F42D /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DB13B1911849DF510010F42D /* ffi.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = ffi.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DBFA713E187F1D8600A76262 /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = "<group>"; };
|
||||
|
@ -66,35 +143,30 @@
|
|||
DBFA7149187F1D8600A76262 /* types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = types.c; sourceTree = "<group>"; };
|
||||
DBFA715E187F1D9B00A76262 /* ffi_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_arm64.h; sourceTree = "<group>"; };
|
||||
DBFA715F187F1D9B00A76262 /* ffi_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_armv7.h; sourceTree = "<group>"; };
|
||||
DBFA7160187F1D9B00A76262 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = "<group>"; };
|
||||
DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = "<group>"; };
|
||||
DBFA7162187F1D9B00A76262 /* fficonfig_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_arm64.h; sourceTree = "<group>"; };
|
||||
DBFA7163187F1D9B00A76262 /* fficonfig_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_armv7.h; sourceTree = "<group>"; };
|
||||
DBFA7164187F1D9B00A76262 /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = "<group>"; };
|
||||
DBFA7165187F1D9B00A76262 /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = "<group>"; };
|
||||
DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_arm64.h; sourceTree = "<group>"; };
|
||||
DBFA7167187F1D9B00A76262 /* ffitarget_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_armv7.h; sourceTree = "<group>"; };
|
||||
DBFA7168187F1D9B00A76262 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; };
|
||||
DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = "<group>"; };
|
||||
DBFA716C187F1D9B00A76262 /* ffi_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_arm64.c; sourceTree = "<group>"; };
|
||||
DBFA716C187F1D9B00A76262 /* ffi_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = ffi_arm64.c; sourceTree = "<group>"; };
|
||||
DBFA716D187F1D9B00A76262 /* sysv_arm64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_arm64.S; sourceTree = "<group>"; };
|
||||
DBFA716F187F1D9B00A76262 /* ffi_armv7.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_armv7.c; sourceTree = "<group>"; };
|
||||
DBFA716F187F1D9B00A76262 /* ffi_armv7.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = ffi_armv7.c; sourceTree = "<group>"; };
|
||||
DBFA7170187F1D9B00A76262 /* sysv_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_armv7.S; sourceTree = "<group>"; };
|
||||
DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = trampoline_armv7.S; sourceTree = "<group>"; };
|
||||
DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = "<group>"; };
|
||||
DBFA7174187F1D9B00A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = "<group>"; };
|
||||
DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; };
|
||||
DBFA7176187F1D9B00A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = "<group>"; };
|
||||
DBFA7182187F1DA100A76262 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = "<group>"; };
|
||||
DBFA7183187F1DA100A76262 /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = "<group>"; };
|
||||
DBFA7184187F1DA100A76262 /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = "<group>"; };
|
||||
DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = "<group>"; };
|
||||
DBFA7186187F1DA100A76262 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; };
|
||||
DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = "<group>"; };
|
||||
DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = "<group>"; };
|
||||
DBFA718B187F1DA100A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = "<group>"; };
|
||||
DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; };
|
||||
DBFA718D187F1DA100A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = "<group>"; };
|
||||
DBFA718A187F1DA100A76262 /* unix64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = unix64_x86_64.S; sourceTree = "<group>"; };
|
||||
DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; };
|
||||
FDB52FC51F6144FA00AA92E6 /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FDDB2F3E1F5D61BC00EF414E /* asmnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asmnames.h; sourceTree = "<group>"; };
|
||||
FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffiw64_x86_64.c; sourceTree = "<group>"; };
|
||||
FDDB2F421F5D68C900EF414E /* internal64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal64.h; sourceTree = "<group>"; };
|
||||
FDDB2F431F5D68C900EF414E /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
|
||||
FDDB2F441F5D68C900EF414E /* win64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = win64_x86_64.S; sourceTree = "<group>"; };
|
||||
FDDB2F621F5D846400EF414E /* libffi.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
|
@ -113,6 +185,8 @@
|
|||
children = (
|
||||
DB13B1661849DF1E0010F42D /* libffi.a */,
|
||||
DB13B1911849DF510010F42D /* ffi.dylib */,
|
||||
FDDB2F621F5D846400EF414E /* libffi.a */,
|
||||
FDB52FC51F6144FA00AA92E6 /* libffi.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -123,7 +197,7 @@
|
|||
DBFA713D187F1D8600A76262 /* include */,
|
||||
DBFA7142187F1D8600A76262 /* src */,
|
||||
);
|
||||
path = "darwin_common";
|
||||
path = darwin_common;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DBFA713D187F1D8600A76262 /* include */ = {
|
||||
|
@ -155,7 +229,7 @@
|
|||
DBFA715D187F1D9B00A76262 /* include */,
|
||||
DBFA716A187F1D9B00A76262 /* src */,
|
||||
);
|
||||
path = "darwin_ios";
|
||||
path = darwin_ios;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DBFA715D187F1D9B00A76262 /* include */ = {
|
||||
|
@ -163,15 +237,12 @@
|
|||
children = (
|
||||
DBFA715E187F1D9B00A76262 /* ffi_arm64.h */,
|
||||
DBFA715F187F1D9B00A76262 /* ffi_armv7.h */,
|
||||
DBFA7160187F1D9B00A76262 /* ffi_i386.h */,
|
||||
DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */,
|
||||
DBFA7162187F1D9B00A76262 /* fficonfig_arm64.h */,
|
||||
DBFA7163187F1D9B00A76262 /* fficonfig_armv7.h */,
|
||||
DBFA7164187F1D9B00A76262 /* fficonfig_i386.h */,
|
||||
DBFA7165187F1D9B00A76262 /* fficonfig_x86_64.h */,
|
||||
DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */,
|
||||
DBFA7167187F1D9B00A76262 /* ffitarget_armv7.h */,
|
||||
DBFA7168187F1D9B00A76262 /* ffitarget_i386.h */,
|
||||
DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */,
|
||||
);
|
||||
path = include;
|
||||
|
@ -190,6 +261,7 @@
|
|||
DBFA716B187F1D9B00A76262 /* aarch64 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
43E9A5DA1D35373600926A8F /* internal.h */,
|
||||
DBFA716C187F1D9B00A76262 /* ffi_arm64.c */,
|
||||
DBFA716D187F1D9B00A76262 /* sysv_arm64.S */,
|
||||
);
|
||||
|
@ -199,9 +271,9 @@
|
|||
DBFA716E187F1D9B00A76262 /* arm */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
43E9A5DB1D35374400926A8F /* internal.h */,
|
||||
DBFA716F187F1D9B00A76262 /* ffi_armv7.c */,
|
||||
DBFA7170187F1D9B00A76262 /* sysv_armv7.S */,
|
||||
DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */,
|
||||
);
|
||||
path = arm;
|
||||
sourceTree = "<group>";
|
||||
|
@ -209,10 +281,12 @@
|
|||
DBFA7172187F1D9B00A76262 /* x86 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */,
|
||||
DBFA7174187F1D9B00A76262 /* darwin_i386.S */,
|
||||
43E9A5DC1D35375400926A8F /* internal.h */,
|
||||
43E9A5DD1D35375400926A8F /* internal64.h */,
|
||||
DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */,
|
||||
DBFA7176187F1D9B00A76262 /* ffi_i386.c */,
|
||||
43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */,
|
||||
43E9A5C61D352C1500926A8F /* unix64_x86_64.S */,
|
||||
43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */,
|
||||
);
|
||||
path = x86;
|
||||
sourceTree = "<group>";
|
||||
|
@ -223,17 +297,14 @@
|
|||
DBFA7181187F1DA100A76262 /* include */,
|
||||
DBFA7188187F1DA100A76262 /* src */,
|
||||
);
|
||||
path = "darwin_osx";
|
||||
path = darwin_osx;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DBFA7181187F1DA100A76262 /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DBFA7182187F1DA100A76262 /* ffi_i386.h */,
|
||||
DBFA7183187F1DA100A76262 /* ffi_x86_64.h */,
|
||||
DBFA7184187F1DA100A76262 /* fficonfig_i386.h */,
|
||||
DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */,
|
||||
DBFA7186187F1DA100A76262 /* ffitarget_i386.h */,
|
||||
DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */,
|
||||
);
|
||||
path = include;
|
||||
|
@ -250,10 +321,13 @@
|
|||
DBFA7189187F1DA100A76262 /* x86 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */,
|
||||
DBFA718B187F1DA100A76262 /* darwin_i386.S */,
|
||||
FDDB2F431F5D68C900EF414E /* internal.h */,
|
||||
FDDB2F421F5D68C900EF414E /* internal64.h */,
|
||||
FDDB2F3E1F5D61BC00EF414E /* asmnames.h */,
|
||||
DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */,
|
||||
DBFA718D187F1DA100A76262 /* ffi_i386.c */,
|
||||
FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */,
|
||||
DBFA718A187F1DA100A76262 /* unix64_x86_64.S */,
|
||||
FDDB2F441F5D68C900EF414E /* win64_x86_64.S */,
|
||||
);
|
||||
path = x86;
|
||||
sourceTree = "<group>";
|
||||
|
@ -270,11 +344,8 @@
|
|||
DBFA714A187F1D8600A76262 /* ffi.h in Headers */,
|
||||
DBFA718F187F1DA100A76262 /* ffi_x86_64.h in Headers */,
|
||||
DBFA7191187F1DA100A76262 /* fficonfig_x86_64.h in Headers */,
|
||||
DBFA718E187F1DA100A76262 /* ffi_i386.h in Headers */,
|
||||
DBFA7190187F1DA100A76262 /* fficonfig_i386.h in Headers */,
|
||||
DBFA714B187F1D8600A76262 /* ffi_common.h in Headers */,
|
||||
DBFA7193187F1DA100A76262 /* ffitarget_x86_64.h in Headers */,
|
||||
DBFA7192187F1DA100A76262 /* ffitarget_i386.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -285,7 +356,7 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DB13B18B1849DF1E0010F42D /* Build configuration list for PBXNativeTarget "libffi-iOS" */;
|
||||
buildPhases = (
|
||||
DB13B3051849E01C0010F42D /* ShellScript */,
|
||||
43B5D3FB1D35480D00D1E1FD /* Run Script */,
|
||||
DB13B1621849DF1E0010F42D /* Sources */,
|
||||
DB13B1641849DF1E0010F42D /* CopyFiles */,
|
||||
);
|
||||
|
@ -315,13 +386,47 @@
|
|||
productReference = DB13B1911849DF510010F42D /* ffi.dylib */;
|
||||
productType = "com.apple.product-type.library.dynamic";
|
||||
};
|
||||
FDB52FB01F6144FA00AA92E6 /* libffi-tvOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = FDB52FC21F6144FA00AA92E6 /* Build configuration list for PBXNativeTarget "libffi-tvOS" */;
|
||||
buildPhases = (
|
||||
FDB52FB11F6144FA00AA92E6 /* Run Script */,
|
||||
FDB52FB21F6144FA00AA92E6 /* Sources */,
|
||||
FDB52FC11F6144FA00AA92E6 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "libffi-tvOS";
|
||||
productName = ffi;
|
||||
productReference = FDB52FC51F6144FA00AA92E6 /* libffi.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
FDDB2F471F5D846400EF414E /* libffi-static-Mac */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = FDDB2F5F1F5D846400EF414E /* Build configuration list for PBXNativeTarget "libffi-static-Mac" */;
|
||||
buildPhases = (
|
||||
FDDB2F481F5D846400EF414E /* ShellScript */,
|
||||
FDDB2F491F5D846400EF414E /* Sources */,
|
||||
FDB52FE11F6156E000AA92E6 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "libffi-static-Mac";
|
||||
productName = ffi;
|
||||
productReference = FDDB2F621F5D846400EF414E /* libffi.a */;
|
||||
productType = "com.apple.product-type.library.dynamic";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
DB13B15C1849DEB70010F42D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0510;
|
||||
LastUpgradeCheck = 0830;
|
||||
};
|
||||
buildConfigurationList = DB13B15F1849DEB70010F42D /* Build configuration list for PBXProject "libffi" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
|
@ -336,24 +441,27 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
DB13B1651849DF1E0010F42D /* libffi-iOS */,
|
||||
FDB52FB01F6144FA00AA92E6 /* libffi-tvOS */,
|
||||
DB13B1901849DF510010F42D /* libffi-Mac */,
|
||||
FDDB2F471F5D846400EF414E /* libffi-static-Mac */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
DB13B3051849E01C0010F42D /* ShellScript */ = {
|
||||
43B5D3FB1D35480D00D1E1FD /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-ios";
|
||||
shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-ios\nfi";
|
||||
};
|
||||
DB13B3061849E0490010F42D /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
@ -366,7 +474,34 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-osx";
|
||||
shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-osx\nfi";
|
||||
};
|
||||
FDB52FB11F6144FA00AA92E6 /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-ios\nfi";
|
||||
};
|
||||
FDDB2F481F5D846400EF414E /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-osx\nfi";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
@ -375,19 +510,18 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
43E9A5C81D352C1500926A8F /* unix64_x86_64.S in Sources */,
|
||||
DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */,
|
||||
DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */,
|
||||
DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */,
|
||||
DBFA714E187F1D8600A76262 /* closures.c in Sources */,
|
||||
DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */,
|
||||
DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */,
|
||||
43B5D3F81D35473200D1E1FD /* ffiw64_x86_64.c in Sources */,
|
||||
DBFA7156187F1D8600A76262 /* prep_cif.c in Sources */,
|
||||
DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */,
|
||||
DBFA7158187F1D8600A76262 /* raw_api.c in Sources */,
|
||||
DBFA7178187F1D9B00A76262 /* sysv_arm64.S in Sources */,
|
||||
DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */,
|
||||
DBFA715A187F1D8600A76262 /* types.c in Sources */,
|
||||
DBFA7177187F1D9B00A76262 /* ffi_arm64.c in Sources */,
|
||||
43B5D3FA1D3547CE00D1E1FD /* win64_x86_64.S in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -396,13 +530,47 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */,
|
||||
DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */,
|
||||
DBFA7157187F1D8600A76262 /* prep_cif.c in Sources */,
|
||||
DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */,
|
||||
FDDB2F411F5D66E200EF414E /* ffiw64_x86_64.c in Sources */,
|
||||
DBFA715B187F1D8600A76262 /* types.c in Sources */,
|
||||
DBFA7159187F1D8600A76262 /* raw_api.c in Sources */,
|
||||
DBFA714F187F1D8600A76262 /* closures.c in Sources */,
|
||||
DBFA7194187F1DA100A76262 /* darwin64_x86_64.S in Sources */,
|
||||
DBFA7194187F1DA100A76262 /* unix64_x86_64.S in Sources */,
|
||||
FDDB2F461F5D691E00EF414E /* win64_x86_64.S in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FDB52FB21F6144FA00AA92E6 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FDB52FB31F6144FA00AA92E6 /* unix64_x86_64.S in Sources */,
|
||||
FDB52FB51F6144FA00AA92E6 /* ffi64_x86_64.c in Sources */,
|
||||
FDB52FB61F6144FA00AA92E6 /* ffi_armv7.c in Sources */,
|
||||
FDB52FB71F6144FA00AA92E6 /* closures.c in Sources */,
|
||||
FDB52FB81F6144FA00AA92E6 /* sysv_armv7.S in Sources */,
|
||||
FDB52FB91F6144FA00AA92E6 /* ffiw64_x86_64.c in Sources */,
|
||||
FDB52FBA1F6144FA00AA92E6 /* prep_cif.c in Sources */,
|
||||
FDB52FBC1F6144FA00AA92E6 /* raw_api.c in Sources */,
|
||||
FDB52FBD1F6144FA00AA92E6 /* sysv_arm64.S in Sources */,
|
||||
FDB52FBE1F6144FA00AA92E6 /* types.c in Sources */,
|
||||
FDB52FBF1F6144FA00AA92E6 /* ffi_arm64.c in Sources */,
|
||||
FDB52FC01F6144FA00AA92E6 /* win64_x86_64.S in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FDDB2F491F5D846400EF414E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FDDB2F4A1F5D846400EF414E /* ffi64_x86_64.c in Sources */,
|
||||
FDDB2F4C1F5D846400EF414E /* prep_cif.c in Sources */,
|
||||
FDDB2F4E1F5D846400EF414E /* ffiw64_x86_64.c in Sources */,
|
||||
FDDB2F4F1F5D846400EF414E /* types.c in Sources */,
|
||||
FDDB2F501F5D846400EF414E /* raw_api.c in Sources */,
|
||||
FDDB2F511F5D846400EF414E /* closures.c in Sources */,
|
||||
FDDB2F521F5D846400EF414E /* unix64_x86_64.S in Sources */,
|
||||
FDDB2F531F5D846400EF414E /* win64_x86_64.S in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -412,9 +580,27 @@
|
|||
DB13B1601849DEB70010F42D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"darwin_common/include",
|
||||
darwin_common/include,
|
||||
);
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
};
|
||||
|
@ -423,9 +609,26 @@
|
|||
DB13B1611849DEB70010F42D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"darwin_common/include",
|
||||
darwin_common/include,
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
|
@ -434,11 +637,6 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
|
@ -449,14 +647,11 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DSTROOT = /tmp/ffi.dst;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
|
@ -465,14 +660,13 @@
|
|||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"darwin_ios/include",
|
||||
darwin_ios/include,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
PRODUCT_NAME = ffi;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
VALID_ARCHS = "arm64 armv7 armv7s x86_64";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -480,11 +674,6 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
|
@ -496,7 +685,6 @@
|
|||
COPY_PHASE_STRIP = YES;
|
||||
DSTROOT = /tmp/ffi.dst;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
|
@ -505,15 +693,14 @@
|
|||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"darwin_ios/include",
|
||||
darwin_ios/include,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
PRODUCT_NAME = ffi;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VALID_ARCHS = "arm64 armv7 armv7s x86_64";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -532,6 +719,7 @@
|
|||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
|
@ -552,7 +740,7 @@
|
|||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"darwin_osx/include",
|
||||
darwin_osx/include,
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
|
@ -577,6 +765,7 @@
|
|||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
@ -592,7 +781,7 @@
|
|||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"darwin_osx/include",
|
||||
darwin_osx/include,
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
OTHER_LDFLAGS = "-Wl,-no_compact_unwind";
|
||||
|
@ -601,6 +790,159 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
FDB52FC31F6144FA00AA92E6 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
darwin_ios/include,
|
||||
);
|
||||
PRODUCT_NAME = ffi;
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
FDB52FC41F6144FA00AA92E6 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
darwin_ios/include,
|
||||
);
|
||||
PRODUCT_NAME = ffi;
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
FDDB2F601F5D846400EF414E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
EXECUTABLE_EXTENSION = a;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
darwin_osx/include,
|
||||
);
|
||||
MACH_O_TYPE = staticlib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = ffi;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
FDDB2F611F5D846400EF414E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
EXECUTABLE_EXTENSION = a;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
darwin_osx/include,
|
||||
);
|
||||
MACH_O_TYPE = staticlib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
PRODUCT_NAME = ffi;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
@ -631,6 +973,24 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
FDB52FC21F6144FA00AA92E6 /* Build configuration list for PBXNativeTarget "libffi-tvOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
FDB52FC31F6144FA00AA92E6 /* Debug */,
|
||||
FDB52FC41F6144FA00AA92E6 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
FDDB2F5F1F5D846400EF414E /* Build configuration list for PBXNativeTarget "libffi-static-Mac" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
FDDB2F601F5D846400EF414E /* Debug */,
|
||||
FDDB2F611F5D846400EF414E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = DB13B15C1849DEB70010F42D /* Project object */;
|
||||
|
|
|
@ -2,5 +2,28 @@
|
|||
# the libtool manual to understand the meaning of the fields. This is
|
||||
# a separate file so that version updates don't involve re-running
|
||||
# automake.
|
||||
#
|
||||
# Here are a set of rules to help you update your library version
|
||||
# information:
|
||||
#
|
||||
# 1. Start with version information of `0:0:0' for each libtool library.
|
||||
#
|
||||
# 2. Update the version information only immediately before a public
|
||||
# release of your software. More frequent updates are unnecessary,
|
||||
# and only guarantee that the current interface number gets larger
|
||||
# faster.
|
||||
#
|
||||
# 3. If the library source code has changed at all since the last
|
||||
# update, then increment revision (`c:r:a' becomes `c:r+1:a').
|
||||
#
|
||||
# 4. If any interfaces have been added, removed, or changed since the
|
||||
# last update, increment current, and set revision to 0.
|
||||
#
|
||||
# 5. If any interfaces have been added since the last public release,
|
||||
# then increment age.
|
||||
#
|
||||
# 6. If any interfaces have been removed since the last public
|
||||
# release, then set age to 0.
|
||||
#
|
||||
# CURRENT:REVISION:AGE
|
||||
7:0:0
|
||||
9:0:1
|
||||
|
|
|
@ -1,515 +0,0 @@
|
|||
# Makefile.in generated by automake 1.15.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2017 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
subdir = man
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
||||
$(top_srcdir)/../config/asmcfi.m4 \
|
||||
$(top_srcdir)/../config/depstand.m4 \
|
||||
$(top_srcdir)/../config/lead-dot.m4 \
|
||||
$(top_srcdir)/../config/multi.m4 \
|
||||
$(top_srcdir)/../config/override.m4 \
|
||||
$(top_srcdir)/../config/toolexeclibdir.m4 \
|
||||
$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
|
||||
$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
|
||||
$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
|
||||
CONFIG_HEADER = $(top_builddir)/fficonfig.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
man3dir = $(mandir)/man3
|
||||
am__installdirs = "$(DESTDIR)$(man3dir)"
|
||||
NROFF = nroff
|
||||
MANS = $(man_MANS)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
ALLOCA = @ALLOCA@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AM_LTLDFLAGS = @AM_LTLDFLAGS@
|
||||
AM_RUNTESTFLAGS = @AM_RUNTESTFLAGS@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FFI_EXEC_TRAMPOLINE_TABLE = @FFI_EXEC_TRAMPOLINE_TABLE@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
HAVE_LONG_DOUBLE = @HAVE_LONG_DOUBLE@
|
||||
HAVE_LONG_DOUBLE_VARIANT = @HAVE_LONG_DOUBLE_VARIANT@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OPT_LDFLAGS = @OPT_LDFLAGS@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SECTION_LDFLAGS = @SECTION_LDFLAGS@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
TARGET = @TARGET@
|
||||
TARGETDIR = @TARGETDIR@
|
||||
TARGET_OBJ = @TARGET_OBJ@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
get_gcc_base_ver = @get_gcc_base_ver@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
multi_basedir = @multi_basedir@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
toolexecdir = @toolexecdir@
|
||||
toolexeclibdir = @toolexeclibdir@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3
|
||||
man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign man/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-man3: $(man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list1=''; \
|
||||
list2='$(man_MANS)'; \
|
||||
test -n "$(man3dir)" \
|
||||
&& test -n "`echo $$list1$$list2`" \
|
||||
|| exit 0; \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \
|
||||
{ for i in $$list1; do echo "$$i"; done; \
|
||||
if test -n "$$list2"; then \
|
||||
for i in $$list2; do echo "$$i"; done \
|
||||
| sed -n '/\.3[a-z]*$$/p'; \
|
||||
fi; \
|
||||
} | while read p; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; echo "$$p"; \
|
||||
done | \
|
||||
sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
|
||||
sed 'N;N;s,\n, ,g' | { \
|
||||
list=; while read file base inst; do \
|
||||
if test "$$base" = "$$inst"; then list="$$list $$file"; else \
|
||||
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
|
||||
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
|
||||
fi; \
|
||||
done; \
|
||||
for i in $$list; do echo "$$i"; done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
|
||||
done; }
|
||||
|
||||
uninstall-man3:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list=''; test -n "$(man3dir)" || exit 0; \
|
||||
files=`{ for i in $$list; do echo "$$i"; done; \
|
||||
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
|
||||
sed -n '/\.3[a-z]*$$/p'; \
|
||||
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
|
||||
dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir)
|
||||
tags TAGS:
|
||||
|
||||
ctags CTAGS:
|
||||
|
||||
cscope cscopelist:
|
||||
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(MANS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(man3dir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-man
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man: install-man3
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-man
|
||||
|
||||
uninstall-man: uninstall-man3
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: all all-am check check-am clean clean-generic clean-libtool \
|
||||
cscopelist-am ctags-am distclean distclean-generic \
|
||||
distclean-libtool dvi dvi-am html html-am info info-am install \
|
||||
install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-man3 install-pdf install-pdf-am install-ps \
|
||||
install-ps-am install-strip installcheck installcheck-am \
|
||||
installdirs maintainer-clean maintainer-clean-generic \
|
||||
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
|
||||
ps ps-am tags-am uninstall uninstall-am uninstall-man \
|
||||
uninstall-man3
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# 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:
|
205
libffi/mdate-sh
205
libffi/mdate-sh
|
@ -1,205 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Get modification time of a file or directory and pretty-print it.
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005, 2007, 2009 Free
|
||||
# Software Foundation, Inc.
|
||||
# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No file. Try \`$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: mdate-sh [--help] [--version] FILE
|
||||
|
||||
Pretty-print the modification time of FILE.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "mdate-sh $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Prevent date giving response in another language.
|
||||
LANG=C
|
||||
export LANG
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
LC_TIME=C
|
||||
export LC_TIME
|
||||
|
||||
# GNU ls changes its time format in response to the TIME_STYLE
|
||||
# variable. Since we cannot assume `unset' works, revert this
|
||||
# variable to its documented default.
|
||||
if test "${TIME_STYLE+set}" = set; then
|
||||
TIME_STYLE=posix-long-iso
|
||||
export TIME_STYLE
|
||||
fi
|
||||
|
||||
save_arg1=$1
|
||||
|
||||
# Find out how to get the extended ls output of a file or directory.
|
||||
if ls -L /dev/null 1>/dev/null 2>&1; then
|
||||
ls_command='ls -L -l -d'
|
||||
else
|
||||
ls_command='ls -l -d'
|
||||
fi
|
||||
# Avoid user/group names that might have spaces, when possible.
|
||||
if ls -n /dev/null 1>/dev/null 2>&1; then
|
||||
ls_command="$ls_command -n"
|
||||
fi
|
||||
|
||||
# A `ls -l' line looks as follows on OS/2.
|
||||
# drwxrwx--- 0 Aug 11 2001 foo
|
||||
# This differs from Unix, which adds ownership information.
|
||||
# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
|
||||
#
|
||||
# To find the date, we split the line on spaces and iterate on words
|
||||
# until we find a month. This cannot work with files whose owner is a
|
||||
# user named `Jan', or `Feb', etc. However, it's unlikely that `/'
|
||||
# will be owned by a user whose name is a month. So we first look at
|
||||
# the extended ls output of the root directory to decide how many
|
||||
# words should be skipped to get the date.
|
||||
|
||||
# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
|
||||
set x`$ls_command /`
|
||||
|
||||
# Find which argument is the month.
|
||||
month=
|
||||
command=
|
||||
until test $month
|
||||
do
|
||||
shift
|
||||
# Add another shift to the command.
|
||||
command="$command shift;"
|
||||
case $1 in
|
||||
Jan) month=January; nummonth=1;;
|
||||
Feb) month=February; nummonth=2;;
|
||||
Mar) month=March; nummonth=3;;
|
||||
Apr) month=April; nummonth=4;;
|
||||
May) month=May; nummonth=5;;
|
||||
Jun) month=June; nummonth=6;;
|
||||
Jul) month=July; nummonth=7;;
|
||||
Aug) month=August; nummonth=8;;
|
||||
Sep) month=September; nummonth=9;;
|
||||
Oct) month=October; nummonth=10;;
|
||||
Nov) month=November; nummonth=11;;
|
||||
Dec) month=December; nummonth=12;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get the extended ls output of the file or directory.
|
||||
set dummy x`eval "$ls_command \"\$save_arg1\""`
|
||||
|
||||
# Remove all preceding arguments
|
||||
eval $command
|
||||
|
||||
# Because of the dummy argument above, month is in $2.
|
||||
#
|
||||
# On a POSIX system, we should have
|
||||
#
|
||||
# $# = 5
|
||||
# $1 = file size
|
||||
# $2 = month
|
||||
# $3 = day
|
||||
# $4 = year or time
|
||||
# $5 = filename
|
||||
#
|
||||
# On Darwin 7.7.0 and 7.6.0, we have
|
||||
#
|
||||
# $# = 4
|
||||
# $1 = day
|
||||
# $2 = month
|
||||
# $3 = year or time
|
||||
# $4 = filename
|
||||
|
||||
# Get the month.
|
||||
case $2 in
|
||||
Jan) month=January; nummonth=1;;
|
||||
Feb) month=February; nummonth=2;;
|
||||
Mar) month=March; nummonth=3;;
|
||||
Apr) month=April; nummonth=4;;
|
||||
May) month=May; nummonth=5;;
|
||||
Jun) month=June; nummonth=6;;
|
||||
Jul) month=July; nummonth=7;;
|
||||
Aug) month=August; nummonth=8;;
|
||||
Sep) month=September; nummonth=9;;
|
||||
Oct) month=October; nummonth=10;;
|
||||
Nov) month=November; nummonth=11;;
|
||||
Dec) month=December; nummonth=12;;
|
||||
esac
|
||||
|
||||
case $3 in
|
||||
???*) day=$1;;
|
||||
*) day=$3; shift;;
|
||||
esac
|
||||
|
||||
# Here we have to deal with the problem that the ls output gives either
|
||||
# the time of day or the year.
|
||||
case $3 in
|
||||
*:*) set `date`; eval year=\$$#
|
||||
case $2 in
|
||||
Jan) nummonthtod=1;;
|
||||
Feb) nummonthtod=2;;
|
||||
Mar) nummonthtod=3;;
|
||||
Apr) nummonthtod=4;;
|
||||
May) nummonthtod=5;;
|
||||
Jun) nummonthtod=6;;
|
||||
Jul) nummonthtod=7;;
|
||||
Aug) nummonthtod=8;;
|
||||
Sep) nummonthtod=9;;
|
||||
Oct) nummonthtod=10;;
|
||||
Nov) nummonthtod=11;;
|
||||
Dec) nummonthtod=12;;
|
||||
esac
|
||||
# For the first six month of the year the time notation can also
|
||||
# be used for files modified in the last year.
|
||||
if (expr $nummonth \> $nummonthtod) > /dev/null;
|
||||
then
|
||||
year=`expr $year - 1`
|
||||
fi;;
|
||||
*) year=$3;;
|
||||
esac
|
||||
|
||||
# The result.
|
||||
echo $day $month $year
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
136
libffi/msvcc.sh
136
libffi/msvcc.sh
|
@ -44,17 +44,29 @@
|
|||
|
||||
args_orig=$@
|
||||
args="-nologo -W3"
|
||||
linkargs=
|
||||
static_crt=
|
||||
debug_crt=
|
||||
cl="cl"
|
||||
ml="ml"
|
||||
safeseh="-safeseh"
|
||||
output=
|
||||
libpaths=
|
||||
libversion=8
|
||||
verbose=
|
||||
|
||||
while [ $# -gt 0 ]
|
||||
do
|
||||
case $1
|
||||
in
|
||||
--verbose)
|
||||
verbose=1
|
||||
shift 1
|
||||
;;
|
||||
--version)
|
||||
args="-help"
|
||||
shift 1
|
||||
;;
|
||||
-fexceptions)
|
||||
# Don't enable exceptions for now.
|
||||
#args="$args -EHac"
|
||||
|
@ -68,9 +80,18 @@ do
|
|||
safeseh=
|
||||
shift 1
|
||||
;;
|
||||
-marm)
|
||||
ml='armasm'
|
||||
safeseh=
|
||||
shift 1
|
||||
;;
|
||||
-marm64)
|
||||
ml='armasm64'
|
||||
safeseh=
|
||||
shift 1
|
||||
;;
|
||||
-clang-cl)
|
||||
cl="clang-cl"
|
||||
safeseh=
|
||||
shift 1
|
||||
;;
|
||||
-O0)
|
||||
|
@ -144,13 +165,44 @@ do
|
|||
shift 1
|
||||
;;
|
||||
-I)
|
||||
args="$args -I$2"
|
||||
includes="$includes -I$2"
|
||||
p=$(cygpath -ma "$2")
|
||||
args="$args -I\"$p\""
|
||||
includes="$includes -I\"$p\""
|
||||
shift 2
|
||||
;;
|
||||
-I*)
|
||||
args="$args $1"
|
||||
includes="$includes $1"
|
||||
p=$(cygpath -ma "${1#-I}")
|
||||
args="$args -I\"$p\""
|
||||
includes="$includes -I\"$p\""
|
||||
shift 1
|
||||
;;
|
||||
-L)
|
||||
p=$(cygpath -ma $2)
|
||||
linkargs="$linkargs -LIBPATH:$p"
|
||||
shift 2
|
||||
;;
|
||||
-L*)
|
||||
p=$(cygpath -ma ${1#-L})
|
||||
linkargs="$linkargs -LIBPATH:$p"
|
||||
shift 1
|
||||
;;
|
||||
-link)
|
||||
# add next argument verbatim to linker args
|
||||
linkargs="$linkargs $2"
|
||||
shift 2
|
||||
;;
|
||||
-l*)
|
||||
case $1
|
||||
in
|
||||
-lffi)
|
||||
linkargs="$linkargs lib${1#-l}-${libversion}.lib"
|
||||
;;
|
||||
*)
|
||||
# ignore other libraries like -lm, hope they are
|
||||
# covered by MSVCRT
|
||||
# linkargs="$linkargs ${1#-l}.lib"
|
||||
;;
|
||||
esac
|
||||
shift 1
|
||||
;;
|
||||
-W|-Wextra)
|
||||
|
@ -166,6 +218,15 @@ do
|
|||
# libffi tests -pedantic with -Wall, so drop it also.
|
||||
shift 1
|
||||
;;
|
||||
-warn)
|
||||
# ignore -warn all from libtool as well.
|
||||
if test "$2" = "all"; then
|
||||
shift 2
|
||||
else
|
||||
args="$args -warn"
|
||||
shift 1
|
||||
fi
|
||||
;;
|
||||
-Werror)
|
||||
args="$args -WX"
|
||||
shift 1
|
||||
|
@ -186,6 +247,7 @@ do
|
|||
else
|
||||
output="-Fe$2"
|
||||
fi
|
||||
armasm_output="-o $2"
|
||||
if [ -n "$assembly" ]; then
|
||||
args="$args $output"
|
||||
else
|
||||
|
@ -194,12 +256,12 @@ do
|
|||
shift 2
|
||||
;;
|
||||
*.S)
|
||||
src=$1
|
||||
src="$(cygpath -ma $1)"
|
||||
assembly="true"
|
||||
shift 1
|
||||
;;
|
||||
*.c)
|
||||
args="$args $1"
|
||||
args="$args $(cygpath -ma $1)"
|
||||
shift 1
|
||||
;;
|
||||
*)
|
||||
|
@ -210,11 +272,16 @@ do
|
|||
esac
|
||||
done
|
||||
|
||||
# If -Zi is specified, certain optimizations are implicitly disabled
|
||||
# by MSVC. Add back those optimizations if this is an optimized build.
|
||||
# NOTE: These arguments must come after all others.
|
||||
if [ -n "$opt" ]; then
|
||||
args="$args -link -OPT:REF -OPT:ICF -INCREMENTAL:NO"
|
||||
if [ -n "$linkargs" ]; then
|
||||
|
||||
# If -Zi is specified, certain optimizations are implicitly disabled
|
||||
# by MSVC. Add back those optimizations if this is an optimized build.
|
||||
# NOTE: These arguments must come after all others.
|
||||
if [ -n "$opt" ]; then
|
||||
linkargs="$linkargs -OPT:REF -OPT:ICF -INCREMENTAL:NO"
|
||||
fi
|
||||
|
||||
args="$args -link $linkargs"
|
||||
fi
|
||||
|
||||
if [ -n "$static_crt" ]; then
|
||||
|
@ -232,12 +299,33 @@ if [ -n "$assembly" ]; then
|
|||
outdir="."
|
||||
fi
|
||||
ppsrc="$outdir/$(basename $src|sed 's/.S$/.asm/g')"
|
||||
echo "$cl -nologo -EP $includes $defines $src > $ppsrc"
|
||||
"$cl" -nologo -EP $includes $defines $src > $ppsrc || exit $?
|
||||
output="$(echo $output | sed 's%/F[dpa][^ ]*%%g')"
|
||||
args="-nologo $safeseh $single $output $ppsrc"
|
||||
|
||||
echo "$ml $args"
|
||||
if [ $ml = "armasm" ]; then
|
||||
defines="$defines -D_M_ARM"
|
||||
fi
|
||||
|
||||
if [ $ml = "armasm64" ]; then
|
||||
defines="$defines -D_M_ARM64"
|
||||
fi
|
||||
|
||||
if test -n "$verbose"; then
|
||||
echo "$cl -nologo -EP $includes $defines $src > $ppsrc"
|
||||
fi
|
||||
|
||||
eval "\"$cl\" -nologo -EP $includes $defines $src" > $ppsrc || exit $?
|
||||
output="$(echo $output | sed 's%/F[dpa][^ ]*%%g')"
|
||||
if [ $ml = "armasm" ]; then
|
||||
args="-nologo -g -oldit $armasm_output $ppsrc -errorReport:prompt"
|
||||
elif [ $ml = "armasm64" ]; then
|
||||
args="-nologo -g $armasm_output $ppsrc -errorReport:prompt"
|
||||
else
|
||||
args="-nologo $safeseh $single $output $ppsrc"
|
||||
fi
|
||||
|
||||
if test -n "$verbose"; then
|
||||
echo "$ml $args"
|
||||
fi
|
||||
|
||||
eval "\"$ml\" $args"
|
||||
result=$?
|
||||
|
||||
|
@ -245,13 +333,21 @@ if [ -n "$assembly" ]; then
|
|||
#mv *.obj $outdir
|
||||
else
|
||||
args="$md $args"
|
||||
echo "$cl $args"
|
||||
|
||||
if test -n "$verbose"; then
|
||||
echo "$cl $args"
|
||||
fi
|
||||
# Return an error code of 1 if an invalid command line parameter is passed
|
||||
# instead of just ignoring it.
|
||||
# instead of just ignoring it. Any output that is not a warning or an
|
||||
# error is filtered so this command behaves more like gcc. cl.exe prints
|
||||
# the name of the compiled file otherwise, which breaks the dejagnu checks
|
||||
# for excess warnings and errors.
|
||||
eval "(\"$cl\" $args 2>&1 1>&3 | \
|
||||
awk '{print \$0} /D9002/ {error=1} END{exit error}' >&2) 3>&1"
|
||||
awk '{print \$0} /D9002/ {error=1} END{exit error}' >&2) 3>&1 | \
|
||||
awk '/warning|error/'"
|
||||
result=$?
|
||||
fi
|
||||
|
||||
exit $result
|
||||
|
||||
# vim: noai:ts=4:sw=4
|
||||
|
|
|
@ -19,12 +19,18 @@ 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. */
|
||||
|
||||
#if defined(__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
#include "internal.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> /* FlushInstructionCache */
|
||||
#endif
|
||||
#include <tramp.h>
|
||||
|
||||
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
||||
all further uses in this file will refer to the 128-bit type. */
|
||||
|
@ -54,6 +60,17 @@ struct call_context
|
|||
UINT64 x[N_X_ARG_REG];
|
||||
};
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
#ifdef __MACH__
|
||||
#ifdef HAVE_PTRAUTH
|
||||
#include <ptrauth.h>
|
||||
#endif
|
||||
#include <mach/vm_param.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if defined (__clang__) && defined (__APPLE__)
|
||||
extern void sys_icache_invalidate (void *start, size_t len);
|
||||
#endif
|
||||
|
@ -65,11 +82,15 @@ ffi_clear_cache (void *start, void *end)
|
|||
sys_icache_invalidate (start, (char *)end - (char *)start);
|
||||
#elif defined (__GNUC__)
|
||||
__builtin___clear_cache (start, end);
|
||||
#elif defined (_WIN32)
|
||||
FlushInstructionCache(GetCurrentProcess(), start, (char*)end - (char*)start);
|
||||
#else
|
||||
#error "Missing builtin to flush instruction cache"
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* A subroutine of is_vfp_type. Given a structure type, return the type code
|
||||
of the first non-structure element. Recurse for structure elements.
|
||||
Return -1 if the structure is in fact empty, i.e. no nested elements. */
|
||||
|
@ -220,7 +241,7 @@ is_vfp_type (const ffi_type *ty)
|
|||
|
||||
/* All tests succeeded. Encode the result. */
|
||||
done:
|
||||
return candidate * 4 + (4 - ele_count);
|
||||
return candidate * 4 + (4 - (int)ele_count);
|
||||
}
|
||||
|
||||
/* Representation of the procedure call argument marshalling
|
||||
|
@ -269,7 +290,7 @@ allocate_to_stack (struct arg_state *state, void *stack,
|
|||
alignment = 8;
|
||||
#endif
|
||||
|
||||
nsaa = ALIGN (nsaa, alignment);
|
||||
nsaa = FFI_ALIGN (nsaa, alignment);
|
||||
state->nsaa = nsaa + size;
|
||||
|
||||
return (char *)stack + nsaa;
|
||||
|
@ -304,10 +325,13 @@ extend_integer_type (void *source, int type)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
void extend_hfa_type (void *dest, void *src, int h);
|
||||
#else
|
||||
static void
|
||||
extend_hfa_type (void *dest, void *src, int h)
|
||||
{
|
||||
int f = h - AARCH64_RET_S4;
|
||||
ssize_t f = h - AARCH64_RET_S4;
|
||||
void *x0;
|
||||
|
||||
asm volatile (
|
||||
|
@ -339,10 +363,10 @@ extend_hfa_type (void *dest, void *src, int h)
|
|||
" b 1f\n"
|
||||
" nop\n"
|
||||
" ldp q16, q17, [%3]\n" /* Q4 */
|
||||
" ldp q18, q19, [%3, #16]\n"
|
||||
" ldp q18, q19, [%3, #32]\n"
|
||||
" b 4f\n"
|
||||
" ldp q16, q17, [%3]\n" /* Q3 */
|
||||
" ldr q18, [%3, #16]\n"
|
||||
" ldr q18, [%3, #32]\n"
|
||||
" b 3f\n"
|
||||
" ldp q16, q17, [%3]\n" /* Q2 */
|
||||
" b 2f\n"
|
||||
|
@ -357,7 +381,11 @@ extend_hfa_type (void *dest, void *src, int h)
|
|||
: "r"(f * 12), "r"(dest), "r"(src)
|
||||
: "memory", "v16", "v17", "v18", "v19");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
void* compress_hfa_type (void *dest, void *src, int h);
|
||||
#else
|
||||
static void *
|
||||
compress_hfa_type (void *dest, void *reg, int h)
|
||||
{
|
||||
|
@ -426,6 +454,7 @@ compress_hfa_type (void *dest, void *reg, int h)
|
|||
}
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Either allocate an appropriate register for the argument type, or if
|
||||
none are available, allocate a stack slot and return a pointer
|
||||
|
@ -443,7 +472,7 @@ allocate_int_to_reg_or_stack (struct call_context *context,
|
|||
return allocate_to_stack (state, stack, size, size);
|
||||
}
|
||||
|
||||
ffi_status
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
{
|
||||
ffi_type *rtype = cif->rtype;
|
||||
|
@ -517,7 +546,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
}
|
||||
|
||||
/* Round the stack up to a multiple of the stack alignment requirement. */
|
||||
cif->bytes = ALIGN(bytes, 16);
|
||||
cif->bytes = (unsigned) FFI_ALIGN(bytes, 16);
|
||||
cif->flags = flags;
|
||||
#if defined (__APPLE__)
|
||||
cif->aarch64_nfixedargs = 0;
|
||||
|
@ -528,14 +557,22 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
|
||||
#if defined (__APPLE__)
|
||||
/* Perform Apple-specific cif processing for variadic calls */
|
||||
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs)
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
|
||||
unsigned int ntotalargs)
|
||||
{
|
||||
ffi_status status = ffi_prep_cif_machdep (cif);
|
||||
cif->aarch64_nfixedargs = nfixedargs;
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs)
|
||||
{
|
||||
ffi_status status = ffi_prep_cif_machdep (cif);
|
||||
cif->flags |= AARCH64_FLAG_VARARG;
|
||||
return status;
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
extern void ffi_call_SYSV (struct call_context *context, void *frame,
|
||||
|
@ -552,7 +589,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
|
|||
void *stack, *frame, *rvalue;
|
||||
struct arg_state state;
|
||||
size_t stack_bytes, rtype_size, rsize;
|
||||
int i, nargs, flags;
|
||||
int i, nargs, flags, isvariadic = 0;
|
||||
ffi_type *rtype;
|
||||
|
||||
flags = cif->flags;
|
||||
|
@ -560,6 +597,12 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
|
|||
rtype_size = rtype->size;
|
||||
stack_bytes = cif->bytes;
|
||||
|
||||
if (flags & AARCH64_FLAG_VARARG)
|
||||
{
|
||||
isvariadic = 1;
|
||||
flags &= ~AARCH64_FLAG_VARARG;
|
||||
}
|
||||
|
||||
/* If the target function returns a structure via hidden pointer,
|
||||
then we cannot allow a null rvalue. Otherwise, mash a null
|
||||
rvalue to void return type. */
|
||||
|
@ -574,11 +617,12 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
|
|||
else if (flags & AARCH64_RET_NEED_COPY)
|
||||
rsize = 16;
|
||||
|
||||
/* Allocate consectutive stack for everything we'll need. */
|
||||
context = alloca (sizeof(struct call_context) + stack_bytes + 32 + rsize);
|
||||
/* Allocate consectutive stack for everything we'll need.
|
||||
The frame uses 40 bytes for: lr, fp, rvalue, flags, sp */
|
||||
context = alloca (sizeof(struct call_context) + stack_bytes + 40 + rsize);
|
||||
stack = context + 1;
|
||||
frame = stack + stack_bytes;
|
||||
rvalue = (rsize ? frame + 32 : orig_rvalue);
|
||||
frame = (void*)((uintptr_t)stack + (uintptr_t)stack_bytes);
|
||||
rvalue = (rsize ? (void*)((uintptr_t)frame + 40) : orig_rvalue);
|
||||
|
||||
arg_init (&state);
|
||||
for (i = 0, nargs = cif->nargs; i < nargs; i++)
|
||||
|
@ -639,16 +683,31 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
|
|||
h = is_vfp_type (ty);
|
||||
if (h)
|
||||
{
|
||||
int elems = 4 - (h & 3);
|
||||
if (state.nsrn + elems <= N_V_ARG_REG)
|
||||
{
|
||||
dest = &context->v[state.nsrn];
|
||||
state.nsrn += elems;
|
||||
extend_hfa_type (dest, a, h);
|
||||
break;
|
||||
}
|
||||
state.nsrn = N_V_ARG_REG;
|
||||
dest = allocate_to_stack (&state, stack, ty->alignment, s);
|
||||
int elems = 4 - (h & 3);
|
||||
if (cif->abi == FFI_WIN64 && isvariadic)
|
||||
{
|
||||
if (state.ngrn + elems <= N_X_ARG_REG)
|
||||
{
|
||||
dest = &context->x[state.ngrn];
|
||||
state.ngrn += elems;
|
||||
extend_hfa_type(dest, a, h);
|
||||
break;
|
||||
}
|
||||
state.nsrn = N_X_ARG_REG;
|
||||
dest = allocate_to_stack(&state, stack, ty->alignment, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.nsrn + elems <= N_V_ARG_REG)
|
||||
{
|
||||
dest = &context->v[state.nsrn];
|
||||
state.nsrn += elems;
|
||||
extend_hfa_type (dest, a, h);
|
||||
break;
|
||||
}
|
||||
state.nsrn = N_V_ARG_REG;
|
||||
dest = allocate_to_stack (&state, stack, ty->alignment, s);
|
||||
}
|
||||
}
|
||||
else if (s > 16)
|
||||
{
|
||||
|
@ -657,6 +716,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
|
|||
the argument is replaced by a pointer to the copy. */
|
||||
a = &avalue[i];
|
||||
t = FFI_TYPE_POINTER;
|
||||
s = sizeof (void *);
|
||||
goto do_pointer;
|
||||
}
|
||||
else
|
||||
|
@ -669,7 +729,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
|
|||
X registers, then the argument is copied into
|
||||
consecutive X registers. */
|
||||
dest = &context->x[state.ngrn];
|
||||
state.ngrn += n;
|
||||
state.ngrn += (unsigned int)n;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -711,6 +771,8 @@ ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
|
|||
ffi_call_int (cif, fn, rvalue, avalue, NULL);
|
||||
}
|
||||
|
||||
#if FFI_CLOSURES
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
|
||||
|
@ -724,239 +786,9 @@ ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
|
|||
|
||||
extern void ffi_closure_SYSV (void) FFI_HIDDEN;
|
||||
extern void ffi_closure_SYSV_V (void) FFI_HIDDEN;
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void *ffi_closure_trampoline_table_page;
|
||||
|
||||
typedef struct ffi_trampoline_table ffi_trampoline_table;
|
||||
typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
|
||||
|
||||
struct ffi_trampoline_table
|
||||
{
|
||||
/* contiguous writable and executable pages */
|
||||
vm_address_t config_page;
|
||||
vm_address_t trampoline_page;
|
||||
|
||||
/* free list tracking */
|
||||
uint16_t free_count;
|
||||
ffi_trampoline_table_entry *free_list;
|
||||
ffi_trampoline_table_entry *free_list_pool;
|
||||
|
||||
ffi_trampoline_table *prev;
|
||||
ffi_trampoline_table *next;
|
||||
};
|
||||
|
||||
struct ffi_trampoline_table_entry
|
||||
{
|
||||
void *(*trampoline) ();
|
||||
ffi_trampoline_table_entry *next;
|
||||
};
|
||||
|
||||
/* The trampoline configuration is placed a page prior to the trampoline's entry point */
|
||||
#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - PAGE_SIZE));
|
||||
|
||||
/* Total number of trampolines that fit in one trampoline table */
|
||||
#define FFI_TRAMPOLINE_COUNT (PAGE_SIZE / FFI_TRAMPOLINE_SIZE)
|
||||
|
||||
static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static ffi_trampoline_table *ffi_trampoline_tables = NULL;
|
||||
|
||||
static ffi_trampoline_table *
|
||||
ffi_trampoline_table_alloc ()
|
||||
{
|
||||
ffi_trampoline_table *table = NULL;
|
||||
|
||||
/* Loop until we can allocate two contiguous pages */
|
||||
while (table == NULL)
|
||||
{
|
||||
vm_address_t config_page = 0x0;
|
||||
kern_return_t kt;
|
||||
|
||||
/* Try to allocate two pages */
|
||||
kt =
|
||||
vm_allocate (mach_task_self (), &config_page, PAGE_SIZE * 2,
|
||||
VM_FLAGS_ANYWHERE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
{
|
||||
fprintf (stderr, "vm_allocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now drop the second half of the allocation to make room for the trampoline table */
|
||||
vm_address_t trampoline_page = config_page + PAGE_SIZE;
|
||||
kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
{
|
||||
fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Remap the trampoline table to directly follow the config page */
|
||||
vm_prot_t cur_prot;
|
||||
vm_prot_t max_prot;
|
||||
|
||||
kt =
|
||||
vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE,
|
||||
mach_task_self (),
|
||||
(vm_address_t) & ffi_closure_trampoline_table_page, FALSE,
|
||||
&cur_prot, &max_prot, VM_INHERIT_SHARE);
|
||||
|
||||
/* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
|
||||
if (kt != KERN_SUCCESS)
|
||||
{
|
||||
/* Log unexpected failures */
|
||||
if (kt != KERN_NO_SPACE)
|
||||
{
|
||||
fprintf (stderr, "vm_remap() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have valid trampoline and config pages */
|
||||
table = calloc (1, sizeof (ffi_trampoline_table));
|
||||
table->free_count = FFI_TRAMPOLINE_COUNT;
|
||||
table->config_page = config_page;
|
||||
table->trampoline_page = trampoline_page;
|
||||
|
||||
/* Create and initialize the free list */
|
||||
table->free_list_pool =
|
||||
calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry));
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < table->free_count; i++)
|
||||
{
|
||||
ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
|
||||
entry->trampoline =
|
||||
(void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
|
||||
|
||||
if (i < table->free_count - 1)
|
||||
entry->next = &table->free_list_pool[i + 1];
|
||||
}
|
||||
|
||||
table->free_list = table->free_list_pool;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void *
|
||||
ffi_closure_alloc (size_t size, void **code)
|
||||
{
|
||||
/* Create the closure */
|
||||
ffi_closure *closure = malloc (size);
|
||||
if (closure == NULL)
|
||||
return NULL;
|
||||
|
||||
pthread_mutex_lock (&ffi_trampoline_lock);
|
||||
|
||||
/* Check for an active trampoline table with available entries. */
|
||||
ffi_trampoline_table *table = ffi_trampoline_tables;
|
||||
if (table == NULL || table->free_list == NULL)
|
||||
{
|
||||
table = ffi_trampoline_table_alloc ();
|
||||
if (table == NULL)
|
||||
{
|
||||
free (closure);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Insert the new table at the top of the list */
|
||||
table->next = ffi_trampoline_tables;
|
||||
if (table->next != NULL)
|
||||
table->next->prev = table;
|
||||
|
||||
ffi_trampoline_tables = table;
|
||||
}
|
||||
|
||||
/* Claim the free entry */
|
||||
ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
|
||||
ffi_trampoline_tables->free_list = entry->next;
|
||||
ffi_trampoline_tables->free_count--;
|
||||
entry->next = NULL;
|
||||
|
||||
pthread_mutex_unlock (&ffi_trampoline_lock);
|
||||
|
||||
/* Initialize the return values */
|
||||
*code = entry->trampoline;
|
||||
closure->trampoline_table = table;
|
||||
closure->trampoline_table_entry = entry;
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
void
|
||||
ffi_closure_free (void *ptr)
|
||||
{
|
||||
ffi_closure *closure = ptr;
|
||||
|
||||
pthread_mutex_lock (&ffi_trampoline_lock);
|
||||
|
||||
/* Fetch the table and entry references */
|
||||
ffi_trampoline_table *table = closure->trampoline_table;
|
||||
ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
|
||||
|
||||
/* Return the entry to the free list */
|
||||
entry->next = table->free_list;
|
||||
table->free_list = entry;
|
||||
table->free_count++;
|
||||
|
||||
/* If all trampolines within this table are free, and at least one other table exists, deallocate
|
||||
* the table */
|
||||
if (table->free_count == FFI_TRAMPOLINE_COUNT
|
||||
&& ffi_trampoline_tables != table)
|
||||
{
|
||||
/* Remove from the list */
|
||||
if (table->prev != NULL)
|
||||
table->prev->next = table->next;
|
||||
|
||||
if (table->next != NULL)
|
||||
table->next->prev = table->prev;
|
||||
|
||||
/* Deallocate pages */
|
||||
kern_return_t kt;
|
||||
kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
|
||||
kt =
|
||||
vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
|
||||
/* Deallocate free list */
|
||||
free (table->free_list_pool);
|
||||
free (table);
|
||||
}
|
||||
else if (ffi_trampoline_tables != table)
|
||||
{
|
||||
/* Otherwise, bump this table to the top of the list */
|
||||
table->prev = NULL;
|
||||
table->next = ffi_trampoline_tables;
|
||||
if (ffi_trampoline_tables != NULL)
|
||||
ffi_trampoline_tables->prev = table;
|
||||
|
||||
ffi_trampoline_tables = table;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&ffi_trampoline_lock);
|
||||
|
||||
/* Free the closure */
|
||||
free (closure);
|
||||
}
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
extern void ffi_closure_SYSV_alt (void) FFI_HIDDEN;
|
||||
extern void ffi_closure_SYSV_V_alt (void) FFI_HIDDEN;
|
||||
#endif
|
||||
|
||||
ffi_status
|
||||
|
@ -966,7 +798,7 @@ ffi_prep_closure_loc (ffi_closure *closure,
|
|||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
if (cif->abi != FFI_SYSV)
|
||||
if (cif->abi != FFI_SYSV && cif->abi != FFI_WIN64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
void (*start)(void);
|
||||
|
@ -977,9 +809,14 @@ ffi_prep_closure_loc (ffi_closure *closure,
|
|||
start = ffi_closure_SYSV;
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
void **config = FFI_TRAMPOLINE_CODELOC_CONFIG (codeloc);
|
||||
#ifdef __MACH__
|
||||
#ifdef HAVE_PTRAUTH
|
||||
codeloc = ptrauth_auth_data(codeloc, ptrauth_key_function_pointer, 0);
|
||||
#endif
|
||||
void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
|
||||
config[0] = closure;
|
||||
config[1] = start;
|
||||
#endif
|
||||
#else
|
||||
static const unsigned char trampoline[16] = {
|
||||
0x90, 0x00, 0x00, 0x58, /* ldr x16, tramp+16 */
|
||||
|
@ -987,12 +824,37 @@ ffi_prep_closure_loc (ffi_closure *closure,
|
|||
0x00, 0x02, 0x1f, 0xd6 /* br x16 */
|
||||
};
|
||||
char *tramp = closure->tramp;
|
||||
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
if (ffi_tramp_is_present(closure))
|
||||
{
|
||||
/* Initialize the static trampoline's parameters. */
|
||||
if (start == ffi_closure_SYSV_V)
|
||||
start = ffi_closure_SYSV_V_alt;
|
||||
else
|
||||
start = ffi_closure_SYSV_alt;
|
||||
ffi_tramp_set_parms (closure->ftramp, start, closure);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the dynamic trampoline. */
|
||||
memcpy (tramp, trampoline, sizeof(trampoline));
|
||||
|
||||
*(UINT64 *)(tramp + 16) = (uintptr_t)start;
|
||||
|
||||
ffi_clear_cache(tramp, tramp + FFI_TRAMPOLINE_SIZE);
|
||||
|
||||
/* Also flush the cache for code mapping. */
|
||||
#ifdef _WIN32
|
||||
// Not using dlmalloc.c for Windows ARM64 builds
|
||||
// so calling ffi_data_to_code_pointer() isn't necessary
|
||||
unsigned char *tramp_code = tramp;
|
||||
#else
|
||||
unsigned char *tramp_code = ffi_data_to_code_pointer (tramp);
|
||||
#endif
|
||||
ffi_clear_cache (tramp_code, tramp_code + FFI_TRAMPOLINE_SIZE);
|
||||
out:
|
||||
#endif
|
||||
|
||||
closure->cif = cif;
|
||||
|
@ -1012,7 +874,7 @@ ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif* cif,
|
|||
{
|
||||
void (*start)(void);
|
||||
|
||||
if (cif->abi != FFI_SYSV)
|
||||
if (cif->abi != FFI_SYSV && cif->abi != FFI_WIN64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
if (cif->flags & AARCH64_FLAG_ARG_V)
|
||||
|
@ -1052,11 +914,18 @@ ffi_closure_SYSV_inner (ffi_cif *cif,
|
|||
void *stack, void *rvalue, void *struct_rvalue)
|
||||
{
|
||||
void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
|
||||
int i, h, nargs, flags;
|
||||
int i, h, nargs, flags, isvariadic = 0;
|
||||
struct arg_state state;
|
||||
|
||||
arg_init (&state);
|
||||
|
||||
flags = cif->flags;
|
||||
if (flags & AARCH64_FLAG_VARARG)
|
||||
{
|
||||
isvariadic = 1;
|
||||
flags &= ~AARCH64_FLAG_VARARG;
|
||||
}
|
||||
|
||||
for (i = 0, nargs = cif->nargs; i < nargs; i++)
|
||||
{
|
||||
ffi_type *ty = cif->arg_types[i];
|
||||
|
@ -1091,58 +960,85 @@ ffi_closure_SYSV_inner (ffi_cif *cif,
|
|||
if (h)
|
||||
{
|
||||
n = 4 - (h & 3);
|
||||
if (state.nsrn + n <= N_V_ARG_REG)
|
||||
{
|
||||
void *reg = &context->v[state.nsrn];
|
||||
state.nsrn += n;
|
||||
if (cif->abi == FFI_WIN64 && isvariadic)
|
||||
{
|
||||
if (state.ngrn + n <= N_X_ARG_REG)
|
||||
{
|
||||
void *reg = &context->x[state.ngrn];
|
||||
state.ngrn += (unsigned int)n;
|
||||
|
||||
/* Eeek! We need a pointer to the structure, however the
|
||||
homogeneous float elements are being passed in individual
|
||||
registers, therefore for float and double the structure
|
||||
is not represented as a contiguous sequence of bytes in
|
||||
our saved register context. We don't need the original
|
||||
contents of the register storage, so we reformat the
|
||||
structure into the same memory. */
|
||||
avalue[i] = compress_hfa_type(reg, reg, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.ngrn = N_X_ARG_REG;
|
||||
state.nsrn = N_V_ARG_REG;
|
||||
avalue[i] = allocate_to_stack(&state, stack,
|
||||
ty->alignment, s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.nsrn + n <= N_V_ARG_REG)
|
||||
{
|
||||
void *reg = &context->v[state.nsrn];
|
||||
state.nsrn += (unsigned int)n;
|
||||
avalue[i] = compress_hfa_type(reg, reg, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.nsrn = N_V_ARG_REG;
|
||||
avalue[i] = allocate_to_stack(&state, stack,
|
||||
ty->alignment, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (s > 16)
|
||||
{
|
||||
/* Replace Composite type of size greater than 16 with a
|
||||
pointer. */
|
||||
avalue[i] = *(void **)
|
||||
allocate_int_to_reg_or_stack (context, &state, stack,
|
||||
sizeof (void *));
|
||||
}
|
||||
else
|
||||
{
|
||||
n = (s + 7) / 8;
|
||||
if (state.ngrn + n <= N_X_ARG_REG)
|
||||
{
|
||||
avalue[i] = &context->x[state.ngrn];
|
||||
state.ngrn += (unsigned int)n;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.ngrn = N_X_ARG_REG;
|
||||
avalue[i] = allocate_to_stack(&state, stack,
|
||||
ty->alignment, s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Eeek! We need a pointer to the structure, however the
|
||||
homogeneous float elements are being passed in individual
|
||||
registers, therefore for float and double the structure
|
||||
is not represented as a contiguous sequence of bytes in
|
||||
our saved register context. We don't need the original
|
||||
contents of the register storage, so we reformat the
|
||||
structure into the same memory. */
|
||||
avalue[i] = compress_hfa_type (reg, reg, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.nsrn = N_V_ARG_REG;
|
||||
avalue[i] = allocate_to_stack (&state, stack,
|
||||
ty->alignment, s);
|
||||
}
|
||||
}
|
||||
else if (s > 16)
|
||||
{
|
||||
/* Replace Composite type of size greater than 16 with a
|
||||
pointer. */
|
||||
avalue[i] = *(void **)
|
||||
allocate_int_to_reg_or_stack (context, &state, stack,
|
||||
sizeof (void *));
|
||||
}
|
||||
else
|
||||
{
|
||||
n = (s + 7) / 8;
|
||||
if (state.ngrn + n <= N_X_ARG_REG)
|
||||
{
|
||||
avalue[i] = &context->x[state.ngrn];
|
||||
state.ngrn += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.ngrn = N_X_ARG_REG;
|
||||
avalue[i] = allocate_to_stack (&state, stack,
|
||||
ty->alignment, s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
default:
|
||||
abort();
|
||||
#if defined (__APPLE__)
|
||||
if (i + 1 == cif->aarch64_nfixedargs)
|
||||
{
|
||||
state.ngrn = N_X_ARG_REG;
|
||||
state.nsrn = N_V_ARG_REG;
|
||||
state.allocating_variadic = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
flags = cif->flags;
|
||||
if (flags & AARCH64_RET_IN_MEM)
|
||||
rvalue = struct_rvalue;
|
||||
|
||||
|
@ -1150,3 +1046,19 @@ ffi_closure_SYSV_inner (ffi_cif *cif,
|
|||
|
||||
return flags;
|
||||
}
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
void *
|
||||
ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
|
||||
{
|
||||
extern void *trampoline_code_table;
|
||||
|
||||
*tramp_size = AARCH64_TRAMP_SIZE;
|
||||
*map_size = AARCH64_TRAMP_MAP_SIZE;
|
||||
return &trampoline_code_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FFI_CLOSURES */
|
||||
|
||||
#endif /* (__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)*/
|
||||
|
|
|
@ -32,6 +32,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|||
#define FFI_SIZEOF_JAVA_RAW 4
|
||||
typedef unsigned long long ffi_arg;
|
||||
typedef signed long long ffi_sarg;
|
||||
#elif defined(_WIN32)
|
||||
#define FFI_SIZEOF_ARG 8
|
||||
typedef unsigned long long ffi_arg;
|
||||
typedef signed long long ffi_sarg;
|
||||
#else
|
||||
typedef unsigned long ffi_arg;
|
||||
typedef signed long ffi_sarg;
|
||||
|
@ -41,34 +45,53 @@ typedef enum ffi_abi
|
|||
{
|
||||
FFI_FIRST_ABI = 0,
|
||||
FFI_SYSV,
|
||||
FFI_WIN64,
|
||||
FFI_LAST_ABI,
|
||||
#if defined(_WIN32)
|
||||
FFI_DEFAULT_ABI = FFI_WIN64
|
||||
#else
|
||||
FFI_DEFAULT_ABI = FFI_SYSV
|
||||
#endif
|
||||
} ffi_abi;
|
||||
#endif
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#if defined (__APPLE__)
|
||||
#define FFI_TRAMPOLINE_SIZE 20
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
#if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
#ifdef __MACH__
|
||||
#define FFI_TRAMPOLINE_SIZE 16
|
||||
#define FFI_TRAMPOLINE_CLOSURE_OFFSET 16
|
||||
#else
|
||||
#error "No trampoline table implementation"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define FFI_TRAMPOLINE_SIZE 24
|
||||
#define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
|
||||
#endif
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned is_variadic
|
||||
#endif
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC
|
||||
|
||||
/* ---- Internal ---- */
|
||||
|
||||
#if defined (__APPLE__)
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs
|
||||
#else
|
||||
/* iOS reserves x18 for the system. Disable Go closures until
|
||||
#elif !defined(_WIN32)
|
||||
/* iOS and Windows reserve x18 for the system. Disable Go closures until
|
||||
a new static chain is chosen. */
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/* No complex type on Windows */
|
||||
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -61,7 +61,40 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|||
|
||||
#define AARCH64_FLAG_ARG_V_BIT 7
|
||||
#define AARCH64_FLAG_ARG_V (1 << AARCH64_FLAG_ARG_V_BIT)
|
||||
#define AARCH64_FLAG_VARARG (1 << 8)
|
||||
|
||||
#define N_X_ARG_REG 8
|
||||
#define N_V_ARG_REG 8
|
||||
#define CALL_CONTEXT_SIZE (N_V_ARG_REG * 16 + N_X_ARG_REG * 8)
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
/*
|
||||
* For the trampoline code table mapping, a mapping size of 16K is chosen to
|
||||
* cover the base page sizes of 4K and 16K.
|
||||
*/
|
||||
#define AARCH64_TRAMP_MAP_SHIFT 14
|
||||
#define AARCH64_TRAMP_MAP_SIZE (1 << AARCH64_TRAMP_MAP_SHIFT)
|
||||
#define AARCH64_TRAMP_SIZE 32
|
||||
|
||||
#endif
|
||||
|
||||
/* Helpers for writing assembly compatible with arm ptr auth */
|
||||
#ifdef LIBFFI_ASM
|
||||
|
||||
#ifdef HAVE_PTRAUTH
|
||||
#define SIGN_LR pacibsp
|
||||
#define SIGN_LR_WITH_REG(x) pacib lr, x
|
||||
#define AUTH_LR_AND_RET retab
|
||||
#define AUTH_LR_WITH_REG(x) autib lr, x
|
||||
#define BRANCH_AND_LINK_TO_REG blraaz
|
||||
#define BRANCH_TO_REG braaz
|
||||
#else
|
||||
#define SIGN_LR
|
||||
#define SIGN_LR_WITH_REG(x)
|
||||
#define AUTH_LR_AND_RET ret
|
||||
#define AUTH_LR_WITH_REG(x)
|
||||
#define BRANCH_AND_LINK_TO_REG blr
|
||||
#define BRANCH_TO_REG br
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@ 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. */
|
||||
|
||||
#if defined(__aarch64__) || defined(__arm64__)
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
@ -77,9 +78,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|||
|
||||
cfi_startproc
|
||||
CNAME(ffi_call_SYSV):
|
||||
/* Sign the lr with x1 since that is where it will be stored */
|
||||
SIGN_LR_WITH_REG(x1)
|
||||
|
||||
/* Use a stack frame allocated by our caller. */
|
||||
cfi_def_cfa(x1, 32);
|
||||
#if defined(HAVE_PTRAUTH) && defined(__APPLE__)
|
||||
/* darwin's libunwind assumes that the cfa is the sp and that's the data
|
||||
* used to sign the lr. In order to allow unwinding through this
|
||||
* function it is necessary to point the cfa at the signing register.
|
||||
*/
|
||||
cfi_def_cfa(x1, 0);
|
||||
#else
|
||||
cfi_def_cfa(x1, 40);
|
||||
#endif
|
||||
stp x29, x30, [x1]
|
||||
mov x9, sp
|
||||
str x9, [x1, #32]
|
||||
mov x29, x1
|
||||
mov sp, x0
|
||||
cfi_def_cfa_register(x29)
|
||||
|
@ -110,13 +124,15 @@ CNAME(ffi_call_SYSV):
|
|||
/* Deallocate the context, leaving the stacked arguments. */
|
||||
add sp, sp, #CALL_CONTEXT_SIZE
|
||||
|
||||
blr x9 /* call fn */
|
||||
BRANCH_AND_LINK_TO_REG x9 /* call fn */
|
||||
|
||||
ldp x3, x4, [x29, #16] /* reload rvalue and flags */
|
||||
|
||||
/* Partially deconstruct the stack frame. */
|
||||
mov sp, x29
|
||||
ldr x9, [x29, #32]
|
||||
mov sp, x9
|
||||
cfi_def_cfa_register (sp)
|
||||
mov x2, x29 /* Preserve for auth */
|
||||
ldp x29, x30, [x29]
|
||||
|
||||
/* Save the return value as directed. */
|
||||
|
@ -130,80 +146,87 @@ CNAME(ffi_call_SYSV):
|
|||
and therefore we want to extend to 64 bits; these types
|
||||
have two consecutive entries allocated for them. */
|
||||
.align 4
|
||||
0: ret /* VOID */
|
||||
0: b 99f /* VOID */
|
||||
nop
|
||||
1: str x0, [x3] /* INT64 */
|
||||
ret
|
||||
b 99f
|
||||
2: stp x0, x1, [x3] /* INT128 */
|
||||
ret
|
||||
b 99f
|
||||
3: brk #1000 /* UNUSED */
|
||||
ret
|
||||
b 99f
|
||||
4: brk #1000 /* UNUSED */
|
||||
ret
|
||||
b 99f
|
||||
5: brk #1000 /* UNUSED */
|
||||
ret
|
||||
b 99f
|
||||
6: brk #1000 /* UNUSED */
|
||||
ret
|
||||
b 99f
|
||||
7: brk #1000 /* UNUSED */
|
||||
ret
|
||||
b 99f
|
||||
8: st4 { v0.s, v1.s, v2.s, v3.s }[0], [x3] /* S4 */
|
||||
ret
|
||||
b 99f
|
||||
9: st3 { v0.s, v1.s, v2.s }[0], [x3] /* S3 */
|
||||
ret
|
||||
b 99f
|
||||
10: stp s0, s1, [x3] /* S2 */
|
||||
ret
|
||||
b 99f
|
||||
11: str s0, [x3] /* S1 */
|
||||
ret
|
||||
b 99f
|
||||
12: st4 { v0.d, v1.d, v2.d, v3.d }[0], [x3] /* D4 */
|
||||
ret
|
||||
b 99f
|
||||
13: st3 { v0.d, v1.d, v2.d }[0], [x3] /* D3 */
|
||||
ret
|
||||
b 99f
|
||||
14: stp d0, d1, [x3] /* D2 */
|
||||
ret
|
||||
b 99f
|
||||
15: str d0, [x3] /* D1 */
|
||||
ret
|
||||
b 99f
|
||||
16: str q3, [x3, #48] /* Q4 */
|
||||
nop
|
||||
17: str q2, [x3, #32] /* Q3 */
|
||||
nop
|
||||
18: stp q0, q1, [x3] /* Q2 */
|
||||
ret
|
||||
b 99f
|
||||
19: str q0, [x3] /* Q1 */
|
||||
ret
|
||||
b 99f
|
||||
20: uxtb w0, w0 /* UINT8 */
|
||||
str x0, [x3]
|
||||
21: ret /* reserved */
|
||||
21: b 99f /* reserved */
|
||||
nop
|
||||
22: uxth w0, w0 /* UINT16 */
|
||||
str x0, [x3]
|
||||
23: ret /* reserved */
|
||||
23: b 99f /* reserved */
|
||||
nop
|
||||
24: mov w0, w0 /* UINT32 */
|
||||
str x0, [x3]
|
||||
25: ret /* reserved */
|
||||
25: b 99f /* reserved */
|
||||
nop
|
||||
26: sxtb x0, w0 /* SINT8 */
|
||||
str x0, [x3]
|
||||
27: ret /* reserved */
|
||||
27: b 99f /* reserved */
|
||||
nop
|
||||
28: sxth x0, w0 /* SINT16 */
|
||||
str x0, [x3]
|
||||
29: ret /* reserved */
|
||||
29: b 99f /* reserved */
|
||||
nop
|
||||
30: sxtw x0, w0 /* SINT32 */
|
||||
str x0, [x3]
|
||||
31: ret /* reserved */
|
||||
31: b 99f /* reserved */
|
||||
nop
|
||||
|
||||
/* Return now that result has been populated. */
|
||||
99:
|
||||
AUTH_LR_WITH_REG(x2)
|
||||
ret
|
||||
|
||||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_call_SYSV)
|
||||
FFI_HIDDEN(CNAME(ffi_call_SYSV))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_call_SYSV), #function
|
||||
.hidden CNAME(ffi_call_SYSV)
|
||||
.size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
|
||||
#endif
|
||||
|
||||
#if FFI_CLOSURES
|
||||
|
||||
/* ffi_closure_SYSV
|
||||
|
||||
Closure invocation glue. This is the low level code invoked directly by
|
||||
|
@ -223,6 +246,7 @@ CNAME(ffi_call_SYSV):
|
|||
.align 4
|
||||
CNAME(ffi_closure_SYSV_V):
|
||||
cfi_startproc
|
||||
SIGN_LR
|
||||
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
||||
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
||||
cfi_rel_offset (x29, 0)
|
||||
|
@ -237,15 +261,16 @@ CNAME(ffi_closure_SYSV_V):
|
|||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_closure_SYSV_V)
|
||||
FFI_HIDDEN(CNAME(ffi_closure_SYSV_V))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_closure_SYSV_V), #function
|
||||
.hidden CNAME(ffi_closure_SYSV_V)
|
||||
.size CNAME(ffi_closure_SYSV_V), . - CNAME(ffi_closure_SYSV_V)
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
cfi_startproc
|
||||
CNAME(ffi_closure_SYSV):
|
||||
SIGN_LR
|
||||
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
||||
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
||||
cfi_rel_offset (x29, 0)
|
||||
|
@ -262,7 +287,9 @@ CNAME(ffi_closure_SYSV):
|
|||
/* Load ffi_closure_inner arguments. */
|
||||
ldp PTR_REG(0), PTR_REG(1), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET] /* load cif, fn */
|
||||
ldr PTR_REG(2), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET+PTR_SIZE*2] /* load user_data */
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
.Ldo_closure:
|
||||
#endif
|
||||
add x3, sp, #16 /* load context */
|
||||
add x4, sp, #ffi_closure_SYSV_FS /* load stack */
|
||||
add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
|
||||
|
@ -296,7 +323,7 @@ CNAME(ffi_closure_SYSV):
|
|||
nop
|
||||
8: ldr s3, [x3, #12] /* S4 */
|
||||
nop
|
||||
9: ldr s2, [x2, #8] /* S3 */
|
||||
9: ldr s2, [x3, #8] /* S3 */
|
||||
nop
|
||||
10: ldp s0, s1, [x3] /* S2 */
|
||||
b 99f
|
||||
|
@ -345,35 +372,109 @@ CNAME(ffi_closure_SYSV):
|
|||
cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS)
|
||||
cfi_restore (x29)
|
||||
cfi_restore (x30)
|
||||
ret
|
||||
AUTH_LR_AND_RET
|
||||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_closure_SYSV)
|
||||
FFI_HIDDEN(CNAME(ffi_closure_SYSV))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_closure_SYSV), #function
|
||||
.hidden CNAME(ffi_closure_SYSV)
|
||||
.size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV)
|
||||
#endif
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
.align 4
|
||||
CNAME(ffi_closure_SYSV_V_alt):
|
||||
/* See the comments above trampoline_code_table. */
|
||||
ldr x17, [sp, #8] /* Load closure in x17 */
|
||||
add sp, sp, #16 /* Restore the stack */
|
||||
b CNAME(ffi_closure_SYSV_V)
|
||||
|
||||
.globl CNAME(ffi_closure_SYSV_V_alt)
|
||||
FFI_HIDDEN(CNAME(ffi_closure_SYSV_V_alt))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_closure_SYSV_V_alt), #function
|
||||
.size CNAME(ffi_closure_SYSV_V_alt), . - CNAME(ffi_closure_SYSV_V_alt)
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
CNAME(ffi_closure_SYSV_alt):
|
||||
/* See the comments above trampoline_code_table. */
|
||||
ldr x17, [sp, #8] /* Load closure in x17 */
|
||||
add sp, sp, #16 /* Restore the stack */
|
||||
b CNAME(ffi_closure_SYSV)
|
||||
|
||||
.globl CNAME(ffi_closure_SYSV_alt)
|
||||
FFI_HIDDEN(CNAME(ffi_closure_SYSV_alt))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_closure_SYSV_alt), #function
|
||||
.size CNAME(ffi_closure_SYSV_alt), . - CNAME(ffi_closure_SYSV_alt)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Below is the definition of the trampoline code table. Each element in
|
||||
* the code table is a trampoline.
|
||||
*/
|
||||
/*
|
||||
* The trampoline uses register x17. It saves the original value of x17 on
|
||||
* the stack.
|
||||
*
|
||||
* The trampoline has two parameters - target code to jump to and data for
|
||||
* the target code. The trampoline extracts the parameters from its parameter
|
||||
* block (see tramp_table_map()). The trampoline saves the data address on
|
||||
* the stack. Finally, it jumps to the target code.
|
||||
*
|
||||
* The target code can choose to:
|
||||
*
|
||||
* - restore the value of x17
|
||||
* - load the data address in a register
|
||||
* - restore the stack pointer to what it was when the trampoline was invoked.
|
||||
*/
|
||||
.align AARCH64_TRAMP_MAP_SHIFT
|
||||
CNAME(trampoline_code_table):
|
||||
.rept AARCH64_TRAMP_MAP_SIZE / AARCH64_TRAMP_SIZE
|
||||
sub sp, sp, #16 /* Make space on the stack */
|
||||
str x17, [sp] /* Save x17 on stack */
|
||||
adr x17, #16376 /* Get data address */
|
||||
ldr x17, [x17] /* Copy data into x17 */
|
||||
str x17, [sp, #8] /* Save data on stack */
|
||||
adr x17, #16372 /* Get code address */
|
||||
ldr x17, [x17] /* Load code address into x17 */
|
||||
br x17 /* Jump to code */
|
||||
.endr
|
||||
|
||||
.globl CNAME(trampoline_code_table)
|
||||
FFI_HIDDEN(CNAME(trampoline_code_table))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(trampoline_code_table), #function
|
||||
.size CNAME(trampoline_code_table), . - CNAME(trampoline_code_table)
|
||||
#endif
|
||||
.align AARCH64_TRAMP_MAP_SHIFT
|
||||
#endif /* FFI_EXEC_STATIC_TRAMP */
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
.align 12
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/machine/vm_param.h>
|
||||
.align PAGE_MAX_SHIFT
|
||||
CNAME(ffi_closure_trampoline_table_page):
|
||||
.rept 16384 / FFI_TRAMPOLINE_SIZE
|
||||
adr x17, -16384
|
||||
adr x16, -16380
|
||||
ldr x16, [x16]
|
||||
ldr x17, [x17]
|
||||
br x16
|
||||
.rept PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE
|
||||
adr x16, -PAGE_MAX_SIZE
|
||||
ldp x17, x16, [x16]
|
||||
br x16
|
||||
nop /* each entry in the trampoline config page is 2*sizeof(void*) so the trampoline itself cannot be smaller than 16 bytes */
|
||||
.endr
|
||||
|
||||
|
||||
.globl CNAME(ffi_closure_trampoline_table_page)
|
||||
FFI_HIDDEN(CNAME(ffi_closure_trampoline_table_page))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_closure_trampoline_table_page), #function
|
||||
.hidden CNAME(ffi_closure_trampoline_table_page)
|
||||
.size CNAME(ffi_closure_trampoline_table_page), . - CNAME(ffi_closure_trampoline_table_page)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* FFI_EXEC_TRAMPOLINE_TABLE */
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
.align 4
|
||||
CNAME(ffi_go_closure_SYSV_V):
|
||||
|
@ -392,9 +493,9 @@ CNAME(ffi_go_closure_SYSV_V):
|
|||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_go_closure_SYSV_V)
|
||||
FFI_HIDDEN(CNAME(ffi_go_closure_SYSV_V))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_go_closure_SYSV_V), #function
|
||||
.hidden CNAME(ffi_go_closure_SYSV_V)
|
||||
.size CNAME(ffi_go_closure_SYSV_V), . - CNAME(ffi_go_closure_SYSV_V)
|
||||
#endif
|
||||
|
||||
|
@ -421,12 +522,14 @@ CNAME(ffi_go_closure_SYSV):
|
|||
cfi_endproc
|
||||
|
||||
.globl CNAME(ffi_go_closure_SYSV)
|
||||
FFI_HIDDEN(CNAME(ffi_go_closure_SYSV))
|
||||
#ifdef __ELF__
|
||||
.type CNAME(ffi_go_closure_SYSV), #function
|
||||
.hidden CNAME(ffi_go_closure_SYSV)
|
||||
.size CNAME(ffi_go_closure_SYSV), . - CNAME(ffi_go_closure_SYSV)
|
||||
#endif
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
#endif /* FFI_CLOSURES */
|
||||
#endif /* __arm64__ */
|
||||
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
|
506
libffi/src/aarch64/win64_armasm.S
Normal file
506
libffi/src/aarch64/win64_armasm.S
Normal file
|
@ -0,0 +1,506 @@
|
|||
/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
#include "internal.h"
|
||||
|
||||
OPT 2 /*disable listing */
|
||||
/* For some macros to add unwind information */
|
||||
#include "ksarm64.h"
|
||||
OPT 1 /*re-enable listing */
|
||||
|
||||
#define BE(X) 0
|
||||
#define PTR_REG(n) x##n
|
||||
#define PTR_SIZE 8
|
||||
|
||||
IMPORT ffi_closure_SYSV_inner
|
||||
EXPORT ffi_call_SYSV
|
||||
EXPORT ffi_closure_SYSV_V
|
||||
EXPORT ffi_closure_SYSV
|
||||
EXPORT extend_hfa_type
|
||||
EXPORT compress_hfa_type
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
EXPORT ffi_go_closure_SYSV_V
|
||||
EXPORT ffi_go_closure_SYSV
|
||||
#endif
|
||||
|
||||
TEXTAREA, ALIGN=8
|
||||
|
||||
/* ffi_call_SYSV
|
||||
extern void ffi_call_SYSV (void *stack, void *frame,
|
||||
void (*fn)(void), void *rvalue,
|
||||
int flags, void *closure);
|
||||
Therefore on entry we have:
|
||||
x0 stack
|
||||
x1 frame
|
||||
x2 fn
|
||||
x3 rvalue
|
||||
x4 flags
|
||||
x5 closure
|
||||
*/
|
||||
|
||||
NESTED_ENTRY ffi_call_SYSV_fake
|
||||
|
||||
/* For unwind information, Windows has to store fp and lr */
|
||||
PROLOG_SAVE_REG_PAIR x29, x30, #-32!
|
||||
|
||||
ALTERNATE_ENTRY ffi_call_SYSV
|
||||
/* Use a stack frame allocated by our caller. */
|
||||
stp x29, x30, [x1]
|
||||
mov x29, x1
|
||||
mov sp, x0
|
||||
|
||||
mov x9, x2 /* save fn */
|
||||
mov x8, x3 /* install structure return */
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
/*mov x18, x5 install static chain */
|
||||
#endif
|
||||
stp x3, x4, [x29, #16] /* save rvalue and flags */
|
||||
|
||||
/* Load the vector argument passing registers, if necessary. */
|
||||
tbz x4, #AARCH64_FLAG_ARG_V_BIT, ffi_call_SYSV_L1
|
||||
ldp q0, q1, [sp, #0]
|
||||
ldp q2, q3, [sp, #32]
|
||||
ldp q4, q5, [sp, #64]
|
||||
ldp q6, q7, [sp, #96]
|
||||
|
||||
ffi_call_SYSV_L1
|
||||
/* Load the core argument passing registers, including
|
||||
the structure return pointer. */
|
||||
ldp x0, x1, [sp, #16*N_V_ARG_REG + 0]
|
||||
ldp x2, x3, [sp, #16*N_V_ARG_REG + 16]
|
||||
ldp x4, x5, [sp, #16*N_V_ARG_REG + 32]
|
||||
ldp x6, x7, [sp, #16*N_V_ARG_REG + 48]
|
||||
|
||||
/* Deallocate the context, leaving the stacked arguments. */
|
||||
add sp, sp, #CALL_CONTEXT_SIZE
|
||||
|
||||
blr x9 /* call fn */
|
||||
|
||||
ldp x3, x4, [x29, #16] /* reload rvalue and flags */
|
||||
|
||||
/* Partially deconstruct the stack frame. */
|
||||
mov sp, x29
|
||||
ldp x29, x30, [x29]
|
||||
|
||||
/* Save the return value as directed. */
|
||||
adr x5, ffi_call_SYSV_return
|
||||
and w4, w4, #AARCH64_RET_MASK
|
||||
add x5, x5, x4, lsl #3
|
||||
br x5
|
||||
|
||||
/* Note that each table entry is 2 insns, and thus 8 bytes.
|
||||
For integer data, note that we're storing into ffi_arg
|
||||
and therefore we want to extend to 64 bits; these types
|
||||
have two consecutive entries allocated for them. */
|
||||
ALIGN 4
|
||||
ffi_call_SYSV_return
|
||||
ret /* VOID */
|
||||
nop
|
||||
str x0, [x3] /* INT64 */
|
||||
ret
|
||||
stp x0, x1, [x3] /* INT128 */
|
||||
ret
|
||||
brk #1000 /* UNUSED */
|
||||
ret
|
||||
brk #1000 /* UNUSED */
|
||||
ret
|
||||
brk #1000 /* UNUSED */
|
||||
ret
|
||||
brk #1000 /* UNUSED */
|
||||
ret
|
||||
brk #1000 /* UNUSED */
|
||||
ret
|
||||
st4 { v0.s, v1.s, v2.s, v3.s }[0], [x3] /* S4 */
|
||||
ret
|
||||
st3 { v0.s, v1.s, v2.s }[0], [x3] /* S3 */
|
||||
ret
|
||||
stp s0, s1, [x3] /* S2 */
|
||||
ret
|
||||
str s0, [x3] /* S1 */
|
||||
ret
|
||||
st4 { v0.d, v1.d, v2.d, v3.d }[0], [x3] /* D4 */
|
||||
ret
|
||||
st3 { v0.d, v1.d, v2.d }[0], [x3] /* D3 */
|
||||
ret
|
||||
stp d0, d1, [x3] /* D2 */
|
||||
ret
|
||||
str d0, [x3] /* D1 */
|
||||
ret
|
||||
str q3, [x3, #48] /* Q4 */
|
||||
nop
|
||||
str q2, [x3, #32] /* Q3 */
|
||||
nop
|
||||
stp q0, q1, [x3] /* Q2 */
|
||||
ret
|
||||
str q0, [x3] /* Q1 */
|
||||
ret
|
||||
uxtb w0, w0 /* UINT8 */
|
||||
str x0, [x3]
|
||||
ret /* reserved */
|
||||
nop
|
||||
uxth w0, w0 /* UINT16 */
|
||||
str x0, [x3]
|
||||
ret /* reserved */
|
||||
nop
|
||||
mov w0, w0 /* UINT32 */
|
||||
str x0, [x3]
|
||||
ret /* reserved */
|
||||
nop
|
||||
sxtb x0, w0 /* SINT8 */
|
||||
str x0, [x3]
|
||||
ret /* reserved */
|
||||
nop
|
||||
sxth x0, w0 /* SINT16 */
|
||||
str x0, [x3]
|
||||
ret /* reserved */
|
||||
nop
|
||||
sxtw x0, w0 /* SINT32 */
|
||||
str x0, [x3]
|
||||
ret /* reserved */
|
||||
nop
|
||||
|
||||
|
||||
NESTED_END ffi_call_SYSV_fake
|
||||
|
||||
|
||||
/* ffi_closure_SYSV
|
||||
Closure invocation glue. This is the low level code invoked directly by
|
||||
the closure trampoline to setup and call a closure.
|
||||
On entry x17 points to a struct ffi_closure, x16 has been clobbered
|
||||
all other registers are preserved.
|
||||
We allocate a call context and save the argument passing registers,
|
||||
then invoked the generic C ffi_closure_SYSV_inner() function to do all
|
||||
the real work, on return we load the result passing registers back from
|
||||
the call context.
|
||||
*/
|
||||
|
||||
#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64)
|
||||
|
||||
NESTED_ENTRY ffi_closure_SYSV_V
|
||||
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
||||
|
||||
/* Save the argument passing vector registers. */
|
||||
stp q0, q1, [sp, #16 + 0]
|
||||
stp q2, q3, [sp, #16 + 32]
|
||||
stp q4, q5, [sp, #16 + 64]
|
||||
stp q6, q7, [sp, #16 + 96]
|
||||
|
||||
b ffi_closure_SYSV_save_argument
|
||||
NESTED_END ffi_closure_SYSV_V
|
||||
|
||||
NESTED_ENTRY ffi_closure_SYSV
|
||||
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
||||
|
||||
ffi_closure_SYSV_save_argument
|
||||
/* Save the argument passing core registers. */
|
||||
stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
|
||||
stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
|
||||
stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
|
||||
stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
|
||||
|
||||
/* Load ffi_closure_inner arguments. */
|
||||
ldp PTR_REG(0), PTR_REG(1), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET] /* load cif, fn */
|
||||
ldr PTR_REG(2), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET+PTR_SIZE*2] /* load user_data */
|
||||
|
||||
do_closure
|
||||
add x3, sp, #16 /* load context */
|
||||
add x4, sp, #ffi_closure_SYSV_FS /* load stack */
|
||||
add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
|
||||
mov x6, x8 /* load struct_rval */
|
||||
|
||||
bl ffi_closure_SYSV_inner
|
||||
|
||||
/* Load the return value as directed. */
|
||||
adr x1, ffi_closure_SYSV_return_base
|
||||
and w0, w0, #AARCH64_RET_MASK
|
||||
add x1, x1, x0, lsl #3
|
||||
add x3, sp, #16+CALL_CONTEXT_SIZE
|
||||
br x1
|
||||
|
||||
/* Note that each table entry is 2 insns, and thus 8 bytes. */
|
||||
ALIGN 8
|
||||
ffi_closure_SYSV_return_base
|
||||
b ffi_closure_SYSV_epilog /* VOID */
|
||||
nop
|
||||
ldr x0, [x3] /* INT64 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
ldp x0, x1, [x3] /* INT128 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
brk #1000 /* UNUSED */
|
||||
nop
|
||||
brk #1000 /* UNUSED */
|
||||
nop
|
||||
brk #1000 /* UNUSED */
|
||||
nop
|
||||
brk #1000 /* UNUSED */
|
||||
nop
|
||||
brk #1000 /* UNUSED */
|
||||
nop
|
||||
ldr s3, [x3, #12] /* S4 */
|
||||
nop
|
||||
ldr s2, [x3, #8] /* S3 */
|
||||
nop
|
||||
ldp s0, s1, [x3] /* S2 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
ldr s0, [x3] /* S1 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
ldr d3, [x3, #24] /* D4 */
|
||||
nop
|
||||
ldr d2, [x3, #16] /* D3 */
|
||||
nop
|
||||
ldp d0, d1, [x3] /* D2 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
ldr d0, [x3] /* D1 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
ldr q3, [x3, #48] /* Q4 */
|
||||
nop
|
||||
ldr q2, [x3, #32] /* Q3 */
|
||||
nop
|
||||
ldp q0, q1, [x3] /* Q2 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
ldr q0, [x3] /* Q1 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
ldrb w0, [x3, #BE(7)] /* UINT8 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
brk #1000 /* reserved */
|
||||
nop
|
||||
ldrh w0, [x3, #BE(6)] /* UINT16 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
brk #1000 /* reserved */
|
||||
nop
|
||||
ldr w0, [x3, #BE(4)] /* UINT32 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
brk #1000 /* reserved */
|
||||
nop
|
||||
ldrsb x0, [x3, #BE(7)] /* SINT8 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
brk #1000 /* reserved */
|
||||
nop
|
||||
ldrsh x0, [x3, #BE(6)] /* SINT16 */
|
||||
b ffi_closure_SYSV_epilog
|
||||
brk #1000 /* reserved */
|
||||
nop
|
||||
ldrsw x0, [x3, #BE(4)] /* SINT32 */
|
||||
nop
|
||||
/* reserved */
|
||||
|
||||
ffi_closure_SYSV_epilog
|
||||
EPILOG_RESTORE_REG_PAIR x29, x30, #ffi_closure_SYSV_FS!
|
||||
EPILOG_RETURN
|
||||
NESTED_END ffi_closure_SYSV
|
||||
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
NESTED_ENTRY ffi_go_closure_SYSV_V
|
||||
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
||||
|
||||
/* Save the argument passing vector registers. */
|
||||
stp q0, q1, [sp, #16 + 0]
|
||||
stp q2, q3, [sp, #16 + 32]
|
||||
stp q4, q5, [sp, #16 + 64]
|
||||
stp q6, q7, [sp, #16 + 96]
|
||||
b ffi_go_closure_SYSV_save_argument
|
||||
NESTED_END ffi_go_closure_SYSV_V
|
||||
|
||||
NESTED_ENTRY ffi_go_closure_SYSV
|
||||
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
||||
|
||||
ffi_go_closure_SYSV_save_argument
|
||||
/* Save the argument passing core registers. */
|
||||
stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
|
||||
stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
|
||||
stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
|
||||
stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
|
||||
|
||||
/* Load ffi_closure_inner arguments. */
|
||||
ldp PTR_REG(0), PTR_REG(1), [x18, #PTR_SIZE]/* load cif, fn */
|
||||
mov x2, x18 /* load user_data */
|
||||
b do_closure
|
||||
NESTED_END ffi_go_closure_SYSV
|
||||
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
|
||||
|
||||
/* void extend_hfa_type (void *dest, void *src, int h) */
|
||||
|
||||
LEAF_ENTRY extend_hfa_type
|
||||
|
||||
adr x3, extend_hfa_type_jump_base
|
||||
and w2, w2, #AARCH64_RET_MASK
|
||||
sub x2, x2, #AARCH64_RET_S4
|
||||
add x3, x3, x2, lsl #4
|
||||
br x3
|
||||
|
||||
ALIGN 4
|
||||
extend_hfa_type_jump_base
|
||||
ldp s16, s17, [x1] /* S4 */
|
||||
ldp s18, s19, [x1, #8]
|
||||
b extend_hfa_type_store_4
|
||||
nop
|
||||
|
||||
ldp s16, s17, [x1] /* S3 */
|
||||
ldr s18, [x1, #8]
|
||||
b extend_hfa_type_store_3
|
||||
nop
|
||||
|
||||
ldp s16, s17, [x1] /* S2 */
|
||||
b extend_hfa_type_store_2
|
||||
nop
|
||||
nop
|
||||
|
||||
ldr s16, [x1] /* S1 */
|
||||
b extend_hfa_type_store_1
|
||||
nop
|
||||
nop
|
||||
|
||||
ldp d16, d17, [x1] /* D4 */
|
||||
ldp d18, d19, [x1, #16]
|
||||
b extend_hfa_type_store_4
|
||||
nop
|
||||
|
||||
ldp d16, d17, [x1] /* D3 */
|
||||
ldr d18, [x1, #16]
|
||||
b extend_hfa_type_store_3
|
||||
nop
|
||||
|
||||
ldp d16, d17, [x1] /* D2 */
|
||||
b extend_hfa_type_store_2
|
||||
nop
|
||||
nop
|
||||
|
||||
ldr d16, [x1] /* D1 */
|
||||
b extend_hfa_type_store_1
|
||||
nop
|
||||
nop
|
||||
|
||||
ldp q16, q17, [x1] /* Q4 */
|
||||
ldp q18, q19, [x1, #16]
|
||||
b extend_hfa_type_store_4
|
||||
nop
|
||||
|
||||
ldp q16, q17, [x1] /* Q3 */
|
||||
ldr q18, [x1, #16]
|
||||
b extend_hfa_type_store_3
|
||||
nop
|
||||
|
||||
ldp q16, q17, [x1] /* Q2 */
|
||||
b extend_hfa_type_store_2
|
||||
nop
|
||||
nop
|
||||
|
||||
ldr q16, [x1] /* Q1 */
|
||||
b extend_hfa_type_store_1
|
||||
|
||||
extend_hfa_type_store_4
|
||||
str q19, [x0, #48]
|
||||
extend_hfa_type_store_3
|
||||
str q18, [x0, #32]
|
||||
extend_hfa_type_store_2
|
||||
str q17, [x0, #16]
|
||||
extend_hfa_type_store_1
|
||||
str q16, [x0]
|
||||
ret
|
||||
|
||||
LEAF_END extend_hfa_type
|
||||
|
||||
|
||||
/* void compress_hfa_type (void *dest, void *reg, int h) */
|
||||
|
||||
LEAF_ENTRY compress_hfa_type
|
||||
|
||||
adr x3, compress_hfa_type_jump_base
|
||||
and w2, w2, #AARCH64_RET_MASK
|
||||
sub x2, x2, #AARCH64_RET_S4
|
||||
add x3, x3, x2, lsl #4
|
||||
br x3
|
||||
|
||||
ALIGN 4
|
||||
compress_hfa_type_jump_base
|
||||
ldp q16, q17, [x1] /* S4 */
|
||||
ldp q18, q19, [x1, #32]
|
||||
st4 { v16.s, v17.s, v18.s, v19.s }[0], [x0]
|
||||
ret
|
||||
|
||||
ldp q16, q17, [x1] /* S3 */
|
||||
ldr q18, [x1, #32]
|
||||
st3 { v16.s, v17.s, v18.s }[0], [x0]
|
||||
ret
|
||||
|
||||
ldp q16, q17, [x1] /* S2 */
|
||||
st2 { v16.s, v17.s }[0], [x0]
|
||||
ret
|
||||
nop
|
||||
|
||||
ldr q16, [x1] /* S1 */
|
||||
st1 { v16.s }[0], [x0]
|
||||
ret
|
||||
nop
|
||||
|
||||
ldp q16, q17, [x1] /* D4 */
|
||||
ldp q18, q19, [x1, #32]
|
||||
st4 { v16.d, v17.d, v18.d, v19.d }[0], [x0]
|
||||
ret
|
||||
|
||||
ldp q16, q17, [x1] /* D3 */
|
||||
ldr q18, [x1, #32]
|
||||
st3 { v16.d, v17.d, v18.d }[0], [x0]
|
||||
ret
|
||||
|
||||
ldp q16, q17, [x1] /* D2 */
|
||||
st2 { v16.d, v17.d }[0], [x0]
|
||||
ret
|
||||
nop
|
||||
|
||||
ldr q16, [x1] /* D1 */
|
||||
st1 { v16.d }[0], [x0]
|
||||
ret
|
||||
nop
|
||||
|
||||
ldp q16, q17, [x1] /* Q4 */
|
||||
ldp q18, q19, [x1, #32]
|
||||
b compress_hfa_type_store_q4
|
||||
nop
|
||||
|
||||
ldp q16, q17, [x1] /* Q3 */
|
||||
ldr q18, [x1, #32]
|
||||
b compress_hfa_type_store_q3
|
||||
nop
|
||||
|
||||
ldp q16, q17, [x1] /* Q2 */
|
||||
stp q16, q17, [x0]
|
||||
ret
|
||||
nop
|
||||
|
||||
ldr q16, [x1] /* Q1 */
|
||||
str q16, [x0]
|
||||
ret
|
||||
|
||||
compress_hfa_type_store_q4
|
||||
str q19, [x0, #48]
|
||||
compress_hfa_type_store_q3
|
||||
str q18, [x0, #32]
|
||||
stp q16, q17, [x0]
|
||||
ret
|
||||
|
||||
LEAF_END compress_hfa_type
|
||||
|
||||
END
|
|
@ -98,7 +98,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
case FFI_TYPE_VOID:
|
||||
case FFI_TYPE_STRUCT:
|
||||
/* Passed by value in N slots. */
|
||||
bytes += ALIGN(itype->size, FFI_SIZEOF_ARG);
|
||||
bytes += FFI_ALIGN(itype->size, FFI_SIZEOF_ARG);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
|
@ -285,7 +285,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
case FFI_TYPE_STRUCT:
|
||||
size = ty->size;
|
||||
memcpy(argp + argn, valp, size);
|
||||
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
|
@ -421,7 +421,7 @@ ffi_closure_osf_inner (ffi_cif *cif,
|
|||
case FFI_TYPE_VOID:
|
||||
case FFI_TYPE_STRUCT:
|
||||
size = ty->size;
|
||||
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
|
|
|
@ -46,12 +46,10 @@ void
|
|||
ffi_prep_args (char *stack, extended_cif * ecif)
|
||||
{
|
||||
unsigned int i;
|
||||
int tmp;
|
||||
void **p_argv;
|
||||
char *argp;
|
||||
ffi_type **p_arg;
|
||||
|
||||
tmp = 0;
|
||||
argp = stack;
|
||||
|
||||
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
|
||||
|
@ -73,7 +71,7 @@ ffi_prep_args (char *stack, extended_cif * ecif)
|
|||
|
||||
/* Align if necessary. */
|
||||
if ((alignment - 1) & (unsigned) argp)
|
||||
argp = (char *) ALIGN (argp, alignment);
|
||||
argp = (char *) FFI_ALIGN (argp, alignment);
|
||||
|
||||
z = (*p_arg)->size;
|
||||
if (z < sizeof (int))
|
||||
|
@ -225,7 +223,7 @@ ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
|
|||
|
||||
/* Align if necessary. */
|
||||
if ((alignment - 1) & (unsigned) argp)
|
||||
argp = (char *) ALIGN (argp, alignment);
|
||||
argp = (char *) FFI_ALIGN (argp, alignment);
|
||||
|
||||
z = (*p_argt)->size;
|
||||
*p_argv = (void *) argp;
|
||||
|
|
|
@ -28,11 +28,42 @@
|
|||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#if defined(__arm__) || defined(_M_ARM)
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <tramp.h>
|
||||
#include "internal.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/machine/vm_param.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN;
|
||||
#else
|
||||
// Declare this as an array of char, instead of array of int,
|
||||
// otherwise Clang optimizes out the "& 0xFFFFFFFE" for clearing
|
||||
// the thumb bit.
|
||||
extern unsigned char ffi_arm_trampoline[12] FFI_HIDDEN;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) && defined(__arm__)
|
||||
#include <sys/types.h>
|
||||
#include <machine/sysarch.h>
|
||||
#endif
|
||||
|
||||
/* Forward declares. */
|
||||
static int vfp_type_p (const ffi_type *);
|
||||
static void layout_vfp_args (ffi_cif *);
|
||||
|
@ -49,7 +80,7 @@ ffi_align (ffi_type *ty, void *p)
|
|||
if (alignment < 4)
|
||||
alignment = 4;
|
||||
#endif
|
||||
return (void *) ALIGN (p, alignment);
|
||||
return (void *) FFI_ALIGN (p, alignment);
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
@ -76,10 +107,20 @@ ffi_put_arg (ffi_type *ty, void *src, void *dst)
|
|||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_POINTER:
|
||||
#ifndef _WIN32
|
||||
case FFI_TYPE_FLOAT:
|
||||
#endif
|
||||
*(UINT32 *)dst = *(UINT32 *)src;
|
||||
break;
|
||||
|
||||
#ifdef _WIN32
|
||||
// casting a float* to a UINT32* doesn't work on Windows
|
||||
case FFI_TYPE_FLOAT:
|
||||
*(uintptr_t *)dst = 0;
|
||||
*(float *)dst = *(float *)src;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
|
@ -95,7 +136,7 @@ ffi_put_arg (ffi_type *ty, void *src, void *dst)
|
|||
abort();
|
||||
}
|
||||
|
||||
return ALIGN (z, 4);
|
||||
return FFI_ALIGN (z, 4);
|
||||
}
|
||||
|
||||
/* ffi_prep_args is called once stack space has been allocated
|
||||
|
@ -198,7 +239,7 @@ ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue,
|
|||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
ffi_status
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
{
|
||||
int flags = 0, cabi = cif->abi;
|
||||
|
@ -276,7 +317,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
/* Round the stack up to a multiple of 8 bytes. This isn't needed
|
||||
everywhere, but it is on some platforms, and it doesn't harm anything
|
||||
when it isn't needed. */
|
||||
bytes = ALIGN (bytes, 8);
|
||||
bytes = FFI_ALIGN (bytes, 8);
|
||||
|
||||
/* Minimum stack space is the 4 register arguments that we pop. */
|
||||
if (bytes < 4*4)
|
||||
|
@ -289,7 +330,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
}
|
||||
|
||||
/* Perform machine dependent cif processing for variadic calls */
|
||||
ffi_status
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep_var (ffi_cif * cif,
|
||||
unsigned int nfixedargs, unsigned int ntotalargs)
|
||||
{
|
||||
|
@ -389,12 +430,14 @@ ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
|
|||
ffi_call_int (cif, fn, rvalue, avalue, NULL);
|
||||
}
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, closure);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *
|
||||
ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue,
|
||||
|
@ -408,6 +451,11 @@ ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue,
|
|||
rvalue = *(void **) argp;
|
||||
argp += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cif->rtype->size && cif->rtype->size < 4)
|
||||
*(uint32_t *) rvalue = 0;
|
||||
}
|
||||
|
||||
for (i = 0, n = cif->nargs; i < n; i++)
|
||||
{
|
||||
|
@ -492,6 +540,8 @@ ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack,
|
|||
return rvalue;
|
||||
}
|
||||
|
||||
#if FFI_CLOSURES
|
||||
|
||||
struct closure_frame
|
||||
{
|
||||
char vfp_space[8*8] __attribute__((aligned(8)));
|
||||
|
@ -527,257 +577,28 @@ ffi_closure_inner_VFP (ffi_cif *cif,
|
|||
|
||||
void ffi_closure_SYSV (void) FFI_HIDDEN;
|
||||
void ffi_closure_VFP (void) FFI_HIDDEN;
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
void ffi_closure_SYSV_alt (void) FFI_HIDDEN;
|
||||
void ffi_closure_VFP_alt (void) FFI_HIDDEN;
|
||||
#endif
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
void ffi_go_closure_SYSV (void) FFI_HIDDEN;
|
||||
void ffi_go_closure_VFP (void) FFI_HIDDEN;
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void *ffi_closure_trampoline_table_page;
|
||||
|
||||
typedef struct ffi_trampoline_table ffi_trampoline_table;
|
||||
typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
|
||||
|
||||
struct ffi_trampoline_table
|
||||
{
|
||||
/* contiguous writable and executable pages */
|
||||
vm_address_t config_page;
|
||||
vm_address_t trampoline_page;
|
||||
|
||||
/* free list tracking */
|
||||
uint16_t free_count;
|
||||
ffi_trampoline_table_entry *free_list;
|
||||
ffi_trampoline_table_entry *free_list_pool;
|
||||
|
||||
ffi_trampoline_table *prev;
|
||||
ffi_trampoline_table *next;
|
||||
};
|
||||
|
||||
struct ffi_trampoline_table_entry
|
||||
{
|
||||
void *(*trampoline) ();
|
||||
ffi_trampoline_table_entry *next;
|
||||
};
|
||||
|
||||
/* Override the standard architecture trampoline size */
|
||||
// XXX TODO - Fix
|
||||
#undef FFI_TRAMPOLINE_SIZE
|
||||
#define FFI_TRAMPOLINE_SIZE 12
|
||||
|
||||
/* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
|
||||
#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
|
||||
|
||||
/* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
|
||||
#define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
|
||||
|
||||
/* Total number of trampolines that fit in one trampoline table */
|
||||
#define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
|
||||
|
||||
static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static ffi_trampoline_table *ffi_trampoline_tables = NULL;
|
||||
|
||||
static ffi_trampoline_table *
|
||||
ffi_trampoline_table_alloc ()
|
||||
{
|
||||
ffi_trampoline_table *table = NULL;
|
||||
|
||||
/* Loop until we can allocate two contiguous pages */
|
||||
while (table == NULL)
|
||||
{
|
||||
vm_address_t config_page = 0x0;
|
||||
kern_return_t kt;
|
||||
|
||||
/* Try to allocate two pages */
|
||||
kt =
|
||||
vm_allocate (mach_task_self (), &config_page, PAGE_SIZE * 2,
|
||||
VM_FLAGS_ANYWHERE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
{
|
||||
fprintf (stderr, "vm_allocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now drop the second half of the allocation to make room for the trampoline table */
|
||||
vm_address_t trampoline_page = config_page + PAGE_SIZE;
|
||||
kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
{
|
||||
fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Remap the trampoline table to directly follow the config page */
|
||||
vm_prot_t cur_prot;
|
||||
vm_prot_t max_prot;
|
||||
|
||||
kt =
|
||||
vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE,
|
||||
mach_task_self (),
|
||||
(vm_address_t) & ffi_closure_trampoline_table_page, FALSE,
|
||||
&cur_prot, &max_prot, VM_INHERIT_SHARE);
|
||||
|
||||
/* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
|
||||
if (kt != KERN_SUCCESS)
|
||||
{
|
||||
/* Log unexpected failures */
|
||||
if (kt != KERN_NO_SPACE)
|
||||
{
|
||||
fprintf (stderr, "vm_remap() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have valid trampoline and config pages */
|
||||
table = calloc (1, sizeof (ffi_trampoline_table));
|
||||
table->free_count = FFI_TRAMPOLINE_COUNT;
|
||||
table->config_page = config_page;
|
||||
table->trampoline_page = trampoline_page;
|
||||
|
||||
/* Create and initialize the free list */
|
||||
table->free_list_pool =
|
||||
calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry));
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < table->free_count; i++)
|
||||
{
|
||||
ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
|
||||
entry->trampoline =
|
||||
(void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
|
||||
|
||||
if (i < table->free_count - 1)
|
||||
entry->next = &table->free_list_pool[i + 1];
|
||||
}
|
||||
|
||||
table->free_list = table->free_list_pool;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void *
|
||||
ffi_closure_alloc (size_t size, void **code)
|
||||
{
|
||||
/* Create the closure */
|
||||
ffi_closure *closure = malloc (size);
|
||||
if (closure == NULL)
|
||||
return NULL;
|
||||
|
||||
pthread_mutex_lock (&ffi_trampoline_lock);
|
||||
|
||||
/* Check for an active trampoline table with available entries. */
|
||||
ffi_trampoline_table *table = ffi_trampoline_tables;
|
||||
if (table == NULL || table->free_list == NULL)
|
||||
{
|
||||
table = ffi_trampoline_table_alloc ();
|
||||
if (table == NULL)
|
||||
{
|
||||
free (closure);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Insert the new table at the top of the list */
|
||||
table->next = ffi_trampoline_tables;
|
||||
if (table->next != NULL)
|
||||
table->next->prev = table;
|
||||
|
||||
ffi_trampoline_tables = table;
|
||||
}
|
||||
|
||||
/* Claim the free entry */
|
||||
ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
|
||||
ffi_trampoline_tables->free_list = entry->next;
|
||||
ffi_trampoline_tables->free_count--;
|
||||
entry->next = NULL;
|
||||
|
||||
pthread_mutex_unlock (&ffi_trampoline_lock);
|
||||
|
||||
/* Initialize the return values */
|
||||
*code = entry->trampoline;
|
||||
closure->trampoline_table = table;
|
||||
closure->trampoline_table_entry = entry;
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
void
|
||||
ffi_closure_free (void *ptr)
|
||||
{
|
||||
ffi_closure *closure = ptr;
|
||||
|
||||
pthread_mutex_lock (&ffi_trampoline_lock);
|
||||
|
||||
/* Fetch the table and entry references */
|
||||
ffi_trampoline_table *table = closure->trampoline_table;
|
||||
ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
|
||||
|
||||
/* Return the entry to the free list */
|
||||
entry->next = table->free_list;
|
||||
table->free_list = entry;
|
||||
table->free_count++;
|
||||
|
||||
/* If all trampolines within this table are free, and at least one other table exists, deallocate
|
||||
* the table */
|
||||
if (table->free_count == FFI_TRAMPOLINE_COUNT
|
||||
&& ffi_trampoline_tables != table)
|
||||
{
|
||||
/* Remove from the list */
|
||||
if (table->prev != NULL)
|
||||
table->prev->next = table->next;
|
||||
|
||||
if (table->next != NULL)
|
||||
table->next->prev = table->prev;
|
||||
|
||||
/* Deallocate pages */
|
||||
kern_return_t kt;
|
||||
kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
|
||||
kt =
|
||||
vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
|
||||
__FILE__, __LINE__);
|
||||
|
||||
/* Deallocate free list */
|
||||
free (table->free_list_pool);
|
||||
free (table);
|
||||
}
|
||||
else if (ffi_trampoline_tables != table)
|
||||
{
|
||||
/* Otherwise, bump this table to the top of the list */
|
||||
table->prev = NULL;
|
||||
table->next = ffi_trampoline_tables;
|
||||
if (ffi_trampoline_tables != NULL)
|
||||
ffi_trampoline_tables->prev = table;
|
||||
|
||||
ffi_trampoline_tables = table;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&ffi_trampoline_lock);
|
||||
|
||||
/* Free the closure */
|
||||
free (closure);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN;
|
||||
|
||||
#endif
|
||||
|
||||
/* the cif must already be prep'ed */
|
||||
|
||||
#if defined(__FreeBSD__) && defined(__arm__)
|
||||
#define __clear_cache(start, end) do { \
|
||||
struct arm_sync_icache_args ua; \
|
||||
\
|
||||
ua.addr = (uintptr_t)(start); \
|
||||
ua.len = (char *)(end) - (char *)start; \
|
||||
sysarch(ARM_SYNC_ICACHE, &ua); \
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure * closure,
|
||||
ffi_cif * cif,
|
||||
|
@ -796,14 +617,47 @@ ffi_prep_closure_loc (ffi_closure * closure,
|
|||
return FFI_BAD_ABI;
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
void **config = FFI_TRAMPOLINE_CODELOC_CONFIG (codeloc);
|
||||
void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
|
||||
config[0] = closure;
|
||||
config[1] = closure_func;
|
||||
#else
|
||||
memcpy (closure->tramp, ffi_arm_trampoline, 8);
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
if (ffi_tramp_is_present(closure))
|
||||
{
|
||||
/* Initialize the static trampoline's parameters. */
|
||||
if (closure_func == ffi_closure_SYSV)
|
||||
closure_func = ffi_closure_SYSV_alt;
|
||||
else
|
||||
closure_func = ffi_closure_VFP_alt;
|
||||
ffi_tramp_set_parms (closure->ftramp, closure_func, closure);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the dynamic trampoline. */
|
||||
#ifndef _WIN32
|
||||
memcpy(closure->tramp, ffi_arm_trampoline, 8);
|
||||
#else
|
||||
// cast away function type so MSVC doesn't set the lower bit of the function pointer
|
||||
memcpy(closure->tramp, (void*)((uintptr_t)ffi_arm_trampoline & 0xFFFFFFFE), FFI_TRAMPOLINE_CLOSURE_OFFSET);
|
||||
#endif
|
||||
|
||||
#if defined (__QNX__)
|
||||
msync(closure->tramp, 8, 0x1000000); /* clear data map */
|
||||
msync(codeloc, 8, 0x1000000); /* clear insn map */
|
||||
#elif defined(_WIN32)
|
||||
FlushInstructionCache(GetCurrentProcess(), closure->tramp, FFI_TRAMPOLINE_SIZE);
|
||||
#else
|
||||
__clear_cache(closure->tramp, closure->tramp + 8); /* clear data map */
|
||||
__clear_cache(codeloc, codeloc + 8); /* clear insn map */
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
*(void(**)(void))(closure->tramp + FFI_TRAMPOLINE_CLOSURE_FUNCTION) = closure_func;
|
||||
#else
|
||||
*(void (**)(void))(closure->tramp + 8) = closure_func;
|
||||
#endif
|
||||
out:
|
||||
#endif
|
||||
|
||||
closure->cif = cif;
|
||||
|
@ -813,6 +667,7 @@ ffi_prep_closure_loc (ffi_closure * closure,
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
|
||||
void (*fun) (ffi_cif *, void *, void **, void *))
|
||||
|
@ -834,6 +689,9 @@ ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
|
|||
|
||||
return FFI_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FFI_CLOSURES */
|
||||
|
||||
/* Below are routines for VFP hard-float support. */
|
||||
|
||||
|
@ -1005,7 +863,7 @@ place_vfp_arg (ffi_cif *cif, int h)
|
|||
}
|
||||
/* Found regs to allocate. */
|
||||
cif->vfp_used |= new_used;
|
||||
cif->vfp_args[cif->vfp_nargs++] = reg;
|
||||
cif->vfp_args[cif->vfp_nargs++] = (signed char)reg;
|
||||
|
||||
/* Update vfp_reg_free. */
|
||||
if (cif->vfp_used & (1 << cif->vfp_reg_free))
|
||||
|
@ -1027,7 +885,7 @@ place_vfp_arg (ffi_cif *cif, int h)
|
|||
static void
|
||||
layout_vfp_args (ffi_cif * cif)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
/* Init VFP fields */
|
||||
cif->vfp_used = 0;
|
||||
cif->vfp_nargs = 0;
|
||||
|
@ -1041,3 +899,17 @@ layout_vfp_args (ffi_cif * cif)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
void *
|
||||
ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
|
||||
{
|
||||
extern void *trampoline_code_table;
|
||||
|
||||
*tramp_size = ARM_TRAMP_SIZE;
|
||||
*map_size = ARM_TRAMP_MAP_SIZE;
|
||||
return &trampoline_code_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __arm__ or _M_ARM */
|
||||
|
|
|
@ -43,7 +43,7 @@ typedef enum ffi_abi {
|
|||
FFI_SYSV,
|
||||
FFI_VFP,
|
||||
FFI_LAST_ABI,
|
||||
#ifdef __ARM_PCS_VFP
|
||||
#if defined(__ARM_PCS_VFP) || defined(_WIN32)
|
||||
FFI_DEFAULT_ABI = FFI_VFP,
|
||||
#else
|
||||
FFI_DEFAULT_ABI = FFI_SYSV,
|
||||
|
@ -57,13 +57,33 @@ typedef enum ffi_abi {
|
|||
signed char vfp_args[16] \
|
||||
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC
|
||||
#ifndef _WIN32
|
||||
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
#endif
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#define FFI_TRAMPOLINE_SIZE 12
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
#if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
#ifdef __MACH__
|
||||
#define FFI_TRAMPOLINE_SIZE 12
|
||||
#define FFI_TRAMPOLINE_CLOSURE_OFFSET 8
|
||||
#else
|
||||
#error "No trampoline table implementation"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#define FFI_TRAMPOLINE_SIZE 16
|
||||
#define FFI_TRAMPOLINE_CLOSURE_FUNCTION 12
|
||||
#else
|
||||
#define FFI_TRAMPOLINE_SIZE 12
|
||||
#endif
|
||||
#define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,3 +5,13 @@
|
|||
#define ARM_TYPE_INT 4
|
||||
#define ARM_TYPE_VOID 5
|
||||
#define ARM_TYPE_STRUCT 6
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
/*
|
||||
* For the trampoline table mapping, a mapping size of 4K (base page size)
|
||||
* is chosen.
|
||||
*/
|
||||
#define ARM_TRAMP_MAP_SHIFT 12
|
||||
#define ARM_TRAMP_MAP_SIZE (1 << ARM_TRAMP_MAP_SHIFT)
|
||||
#define ARM_TRAMP_SIZE 20
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#ifdef __arm__
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
|
@ -52,11 +53,12 @@
|
|||
#endif
|
||||
|
||||
/* Conditionally compile unwinder directives. */
|
||||
.macro UNWIND text:vararg
|
||||
#ifdef __ARM_EABI__
|
||||
\text
|
||||
#endif
|
||||
.endm
|
||||
# define UNWIND(...) __VA_ARGS__
|
||||
#else
|
||||
# define UNWIND(...)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
|
||||
.cfi_sections .debug_frame
|
||||
#endif
|
||||
|
@ -77,29 +79,52 @@
|
|||
# define TYPE(X, Y)
|
||||
#endif
|
||||
|
||||
#define ARM_FUNC_START(name, gl) \
|
||||
.align 3; \
|
||||
.ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \
|
||||
TYPE(name, %function); \
|
||||
#define ARM_FUNC_START_LOCAL(name) \
|
||||
.align 3; \
|
||||
TYPE(CNAME(name), %function); \
|
||||
CNAME(name):
|
||||
|
||||
#define ARM_FUNC_START(name) \
|
||||
.globl CNAME(name); \
|
||||
FFI_HIDDEN(CNAME(name)); \
|
||||
ARM_FUNC_START_LOCAL(name)
|
||||
|
||||
#define ARM_FUNC_END(name) \
|
||||
SIZE(name)
|
||||
|
||||
/* Aid in defining a jump table with 8 bytes between entries. */
|
||||
.macro E index
|
||||
.if . - 0b - 8*\index
|
||||
.error "type table out of sync"
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
#if defined(_WIN32)
|
||||
/* Windows on ARM is thumb-only */
|
||||
.thumb
|
||||
#else
|
||||
/* Keep the assembly in ARM mode in other cases, for simplicity
|
||||
* (to avoid interworking issues). */
|
||||
#undef __thumb__
|
||||
.arm
|
||||
#endif
|
||||
|
||||
/* Aid in defining a jump table with 8 bytes between entries. */
|
||||
#ifdef __thumb__
|
||||
/* In thumb mode, instructions can be shorter than expected in arm mode, so
|
||||
* we need to align the start of each case. */
|
||||
# define E(index) .align 3
|
||||
#elif defined(__clang__)
|
||||
/* ??? The clang assembler doesn't handle .if with symbolic expressions. */
|
||||
# define E(index)
|
||||
#else
|
||||
# define E(index) \
|
||||
.if . - 0b - 8*index; \
|
||||
.error "type table out of sync"; \
|
||||
.endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __clang__
|
||||
/* We require interworking on LDM, which implies ARMv5T,
|
||||
which implies the existance of BLX. */
|
||||
.arch armv5t
|
||||
.arch armv5t
|
||||
#endif
|
||||
|
||||
/* Note that we use STC and LDC to encode VFP instructions,
|
||||
so that we do not need ".fpu vfp", nor get that added to
|
||||
|
@ -111,25 +136,31 @@
|
|||
@ r2: fn
|
||||
@ r3: vfp_used
|
||||
|
||||
ARM_FUNC_START(ffi_call_VFP, 1)
|
||||
UNWIND .fnstart
|
||||
ARM_FUNC_START(ffi_call_VFP)
|
||||
UNWIND(.fnstart)
|
||||
cfi_startproc
|
||||
|
||||
cmp r3, #3 @ load only d0 if possible
|
||||
ldcle p11, cr0, [r0] @ vldrle d0, [sp]
|
||||
ldcgt p11, cr0, [r0], {16} @ vldmgt sp, {d0-d7}
|
||||
ite le
|
||||
#ifdef __clang__
|
||||
vldrle d0, [r0]
|
||||
vldmgt r0, {d0-d7}
|
||||
#else
|
||||
ldcle p11, cr0, [r0] @ vldrle d0, [r0]
|
||||
ldcgt p11, cr0, [r0], {16} @ vldmgt r0, {d0-d7}
|
||||
#endif
|
||||
add r0, r0, #64 @ discard the vfp register args
|
||||
/* FALLTHRU */
|
||||
ARM_FUNC_END(ffi_call_VFP)
|
||||
|
||||
ARM_FUNC_START(ffi_call_SYSV, 1)
|
||||
ARM_FUNC_START(ffi_call_SYSV)
|
||||
stm r1, {fp, lr}
|
||||
mov fp, r1
|
||||
|
||||
@ This is a bit of a lie wrt the origin of the unwind info, but
|
||||
@ now we've got the usual frame pointer and two saved registers.
|
||||
UNWIND .save {fp,lr}
|
||||
UNWIND .setfp fp, sp
|
||||
UNWIND(.save {fp,lr})
|
||||
UNWIND(.setfp fp, sp)
|
||||
cfi_def_cfa(fp, 8)
|
||||
cfi_rel_offset(fp, 0)
|
||||
cfi_rel_offset(lr, 4)
|
||||
|
@ -150,41 +181,61 @@ ARM_FUNC_START(ffi_call_SYSV, 1)
|
|||
cfi_def_cfa_register(sp)
|
||||
|
||||
@ Store values stored in registers.
|
||||
#ifndef __thumb__
|
||||
.align 3
|
||||
add pc, pc, r3, lsl #3
|
||||
nop
|
||||
#else
|
||||
adr ip, 0f
|
||||
add ip, ip, r3, lsl #3
|
||||
mov pc, ip
|
||||
.align 3
|
||||
#endif
|
||||
0:
|
||||
E ARM_TYPE_VFP_S
|
||||
E(ARM_TYPE_VFP_S)
|
||||
#ifdef __clang__
|
||||
vstr s0, [r2]
|
||||
#else
|
||||
stc p10, cr0, [r2] @ vstr s0, [r2]
|
||||
#endif
|
||||
pop {fp,pc}
|
||||
E ARM_TYPE_VFP_D
|
||||
E(ARM_TYPE_VFP_D)
|
||||
#ifdef __clang__
|
||||
vstr d0, [r2]
|
||||
#else
|
||||
stc p11, cr0, [r2] @ vstr d0, [r2]
|
||||
#endif
|
||||
pop {fp,pc}
|
||||
E ARM_TYPE_VFP_N
|
||||
E(ARM_TYPE_VFP_N)
|
||||
#ifdef __clang__
|
||||
vstm r2, {d0-d3}
|
||||
#else
|
||||
stc p11, cr0, [r2], {8} @ vstm r2, {d0-d3}
|
||||
#endif
|
||||
pop {fp,pc}
|
||||
E ARM_TYPE_INT64
|
||||
E(ARM_TYPE_INT64)
|
||||
str r1, [r2, #4]
|
||||
nop
|
||||
E ARM_TYPE_INT
|
||||
E(ARM_TYPE_INT)
|
||||
str r0, [r2]
|
||||
pop {fp,pc}
|
||||
E ARM_TYPE_VOID
|
||||
E(ARM_TYPE_VOID)
|
||||
pop {fp,pc}
|
||||
nop
|
||||
E ARM_TYPE_STRUCT
|
||||
E(ARM_TYPE_STRUCT)
|
||||
pop {fp,pc}
|
||||
|
||||
cfi_endproc
|
||||
UNWIND .fnend
|
||||
UNWIND(.fnend)
|
||||
ARM_FUNC_END(ffi_call_SYSV)
|
||||
|
||||
#if FFI_CLOSURES
|
||||
|
||||
/*
|
||||
int ffi_closure_inner_* (cif, fun, user_data, frame)
|
||||
*/
|
||||
|
||||
ARM_FUNC_START(ffi_go_closure_SYSV, 1)
|
||||
ARM_FUNC_START(ffi_go_closure_SYSV)
|
||||
cfi_startproc
|
||||
stmdb sp!, {r0-r3} @ save argument regs
|
||||
cfi_adjust_cfa_offset(16)
|
||||
|
@ -195,14 +246,21 @@ ARM_FUNC_START(ffi_go_closure_SYSV, 1)
|
|||
cfi_endproc
|
||||
ARM_FUNC_END(ffi_go_closure_SYSV)
|
||||
|
||||
ARM_FUNC_START(ffi_closure_SYSV, 1)
|
||||
UNWIND .fnstart
|
||||
ARM_FUNC_START(ffi_closure_SYSV)
|
||||
UNWIND(.fnstart)
|
||||
cfi_startproc
|
||||
#ifdef _WIN32
|
||||
ldmfd sp!, {r0, ip} @ restore fp (r0 is used for stack alignment)
|
||||
#endif
|
||||
stmdb sp!, {r0-r3} @ save argument regs
|
||||
cfi_adjust_cfa_offset(16)
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
ldr ip, [ip] @ ip points to the config page, dereference to get the ffi_closure*
|
||||
#endif
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] @ load cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] @ load fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] @ load user_data
|
||||
0:
|
||||
add ip, sp, #16 @ compute entry sp
|
||||
sub sp, sp, #64+32 @ allocate frame
|
||||
|
@ -212,7 +270,7 @@ ARM_FUNC_START(ffi_closure_SYSV, 1)
|
|||
/* Remember that EABI unwind info only applies at call sites.
|
||||
We need do nothing except note the save of the stack pointer
|
||||
and the link registers. */
|
||||
UNWIND .save {sp,lr}
|
||||
UNWIND(.save {sp,lr})
|
||||
cfi_adjust_cfa_offset(8)
|
||||
cfi_rel_offset(lr, 4)
|
||||
|
||||
|
@ -222,12 +280,17 @@ ARM_FUNC_START(ffi_closure_SYSV, 1)
|
|||
@ Load values returned in registers.
|
||||
add r2, sp, #8+64 @ load result
|
||||
adr r3, CNAME(ffi_closure_ret)
|
||||
#ifndef __thumb__
|
||||
add pc, r3, r0, lsl #3
|
||||
#else
|
||||
add r3, r3, r0, lsl #3
|
||||
mov pc, r3
|
||||
#endif
|
||||
cfi_endproc
|
||||
UNWIND .fnend
|
||||
UNWIND(.fnend)
|
||||
ARM_FUNC_END(ffi_closure_SYSV)
|
||||
|
||||
ARM_FUNC_START(ffi_go_closure_VFP, 1)
|
||||
ARM_FUNC_START(ffi_go_closure_VFP)
|
||||
cfi_startproc
|
||||
stmdb sp!, {r0-r3} @ save argument regs
|
||||
cfi_adjust_cfa_offset(16)
|
||||
|
@ -238,23 +301,34 @@ ARM_FUNC_START(ffi_go_closure_VFP, 1)
|
|||
cfi_endproc
|
||||
ARM_FUNC_END(ffi_go_closure_VFP)
|
||||
|
||||
ARM_FUNC_START(ffi_closure_VFP, 1)
|
||||
UNWIND .fnstart
|
||||
ARM_FUNC_START(ffi_closure_VFP)
|
||||
UNWIND(.fnstart)
|
||||
cfi_startproc
|
||||
#ifdef _WIN32
|
||||
ldmfd sp!, {r0, ip} @ restore fp (r0 is used for stack alignment)
|
||||
#endif
|
||||
stmdb sp!, {r0-r3} @ save argument regs
|
||||
cfi_adjust_cfa_offset(16)
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
ldr ip, [ip] @ ip points to the config page, dereference to get the ffi_closure*
|
||||
#endif
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] @ load cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] @ load fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] @ load user_data
|
||||
0:
|
||||
add ip, sp, #16
|
||||
sub sp, sp, #64+32 @ allocate frame
|
||||
cfi_adjust_cfa_offset(64+32)
|
||||
#ifdef __clang__
|
||||
vstm sp, {d0-d7}
|
||||
#else
|
||||
stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7}
|
||||
#endif
|
||||
stmdb sp!, {ip,lr}
|
||||
|
||||
/* See above. */
|
||||
UNWIND .save {sp,lr}
|
||||
UNWIND(.save {sp,lr})
|
||||
cfi_adjust_cfa_offset(8)
|
||||
cfi_rel_offset(lr, 4)
|
||||
|
||||
|
@ -264,71 +338,151 @@ ARM_FUNC_START(ffi_closure_VFP, 1)
|
|||
@ Load values returned in registers.
|
||||
add r2, sp, #8+64 @ load result
|
||||
adr r3, CNAME(ffi_closure_ret)
|
||||
#ifndef __thumb__
|
||||
add pc, r3, r0, lsl #3
|
||||
#else
|
||||
add r3, r3, r0, lsl #3
|
||||
mov pc, r3
|
||||
#endif
|
||||
cfi_endproc
|
||||
UNWIND .fnend
|
||||
UNWIND(.fnend)
|
||||
ARM_FUNC_END(ffi_closure_VFP)
|
||||
|
||||
/* Load values returned in registers for both closure entry points.
|
||||
Note that we use LDM with SP in the register set. This is deprecated
|
||||
by ARM, but not yet unpredictable. */
|
||||
|
||||
ARM_FUNC_START(ffi_closure_ret, 0)
|
||||
ARM_FUNC_START_LOCAL(ffi_closure_ret)
|
||||
cfi_startproc
|
||||
cfi_rel_offset(sp, 0)
|
||||
cfi_rel_offset(lr, 4)
|
||||
0:
|
||||
E ARM_TYPE_VFP_S
|
||||
E(ARM_TYPE_VFP_S)
|
||||
#ifdef __clang__
|
||||
vldr s0, [r2]
|
||||
#else
|
||||
ldc p10, cr0, [r2] @ vldr s0, [r2]
|
||||
ldm sp, {sp,pc}
|
||||
E ARM_TYPE_VFP_D
|
||||
#endif
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_VFP_D)
|
||||
#ifdef __clang__
|
||||
vldr d0, [r2]
|
||||
#else
|
||||
ldc p11, cr0, [r2] @ vldr d0, [r2]
|
||||
ldm sp, {sp,pc}
|
||||
E ARM_TYPE_VFP_N
|
||||
#endif
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_VFP_N)
|
||||
#ifdef __clang__
|
||||
vldm r2, {d0-d3}
|
||||
#else
|
||||
ldc p11, cr0, [r2], {8} @ vldm r2, {d0-d3}
|
||||
ldm sp, {sp,pc}
|
||||
E ARM_TYPE_INT64
|
||||
#endif
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_INT64)
|
||||
ldr r1, [r2, #4]
|
||||
nop
|
||||
E ARM_TYPE_INT
|
||||
E(ARM_TYPE_INT)
|
||||
ldr r0, [r2]
|
||||
ldm sp, {sp,pc}
|
||||
E ARM_TYPE_VOID
|
||||
ldm sp, {sp,pc}
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_VOID)
|
||||
b call_epilogue
|
||||
nop
|
||||
E ARM_TYPE_STRUCT
|
||||
E(ARM_TYPE_STRUCT)
|
||||
b call_epilogue
|
||||
call_epilogue:
|
||||
#ifndef __thumb__
|
||||
ldm sp, {sp,pc}
|
||||
#else
|
||||
ldm sp, {ip,lr}
|
||||
mov sp, ip
|
||||
bx lr
|
||||
#endif
|
||||
cfi_endproc
|
||||
ARM_FUNC_END(ffi_closure_ret)
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
ARM_FUNC_START(ffi_closure_SYSV_alt)
|
||||
/* See the comments above trampoline_code_table. */
|
||||
ldr ip, [sp, #4] /* Load closure in ip */
|
||||
add sp, sp, 8 /* Restore the stack */
|
||||
b CNAME(ffi_closure_SYSV)
|
||||
ARM_FUNC_END(ffi_closure_SYSV_alt)
|
||||
|
||||
ARM_FUNC_START(ffi_closure_VFP_alt)
|
||||
/* See the comments above trampoline_code_table. */
|
||||
ldr ip, [sp, #4] /* Load closure in ip */
|
||||
add sp, sp, 8 /* Restore the stack */
|
||||
b CNAME(ffi_closure_VFP)
|
||||
ARM_FUNC_END(ffi_closure_VFP_alt)
|
||||
|
||||
/*
|
||||
* Below is the definition of the trampoline code table. Each element in
|
||||
* the code table is a trampoline.
|
||||
*/
|
||||
/*
|
||||
* The trampoline uses register ip (r12). It saves the original value of ip
|
||||
* on the stack.
|
||||
*
|
||||
* The trampoline has two parameters - target code to jump to and data for
|
||||
* the target code. The trampoline extracts the parameters from its parameter
|
||||
* block (see tramp_table_map()). The trampoline saves the data address on
|
||||
* the stack. Finally, it jumps to the target code.
|
||||
*
|
||||
* The target code can choose to:
|
||||
*
|
||||
* - restore the value of ip
|
||||
* - load the data address in a register
|
||||
* - restore the stack pointer to what it was when the trampoline was invoked.
|
||||
*/
|
||||
.align ARM_TRAMP_MAP_SHIFT
|
||||
ARM_FUNC_START(trampoline_code_table)
|
||||
.rept ARM_TRAMP_MAP_SIZE / ARM_TRAMP_SIZE
|
||||
sub sp, sp, #8 /* Make space on the stack */
|
||||
str ip, [sp] /* Save ip on stack */
|
||||
ldr ip, [pc, #4080] /* Copy data into ip */
|
||||
str ip, [sp, #4] /* Save data on stack */
|
||||
ldr pc, [pc, #4076] /* Copy code into PC */
|
||||
.endr
|
||||
ARM_FUNC_END(trampoline_code_table)
|
||||
.align ARM_TRAMP_MAP_SHIFT
|
||||
#endif /* FFI_EXEC_STATIC_TRAMP */
|
||||
|
||||
#endif /* FFI_CLOSURES */
|
||||
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
/* ??? The iOS support should be updated. The first insn used to
|
||||
be STMFD, but that's been moved into ffi_closure_SYSV. If the
|
||||
writable page is put after this one we can make use of the
|
||||
pc+8 feature of the architecture. We can also reduce the size
|
||||
of the thunk to 8 and pack more of these into the page.
|
||||
#ifdef __MACH__
|
||||
#include <mach/machine/vm_param.h>
|
||||
|
||||
In the meantime, simply replace the STMFD with a NOP so as to
|
||||
keep all the magic numbers the same within ffi.c. */
|
||||
|
||||
.align 12
|
||||
.align PAGE_MAX_SHIFT
|
||||
ARM_FUNC_START(ffi_closure_trampoline_table_page)
|
||||
.rept 4096 / 12
|
||||
nop
|
||||
ldr ip, [pc, #-4092]
|
||||
ldr pc, [pc, #-4092]
|
||||
.rept PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE
|
||||
adr ip, #-PAGE_MAX_SIZE @ the config page is PAGE_MAX_SIZE behind the trampoline page
|
||||
sub ip, #8 @ account for pc bias
|
||||
ldr pc, [ip, #4] @ jump to ffi_closure_SYSV or ffi_closure_VFP
|
||||
.endr
|
||||
ARM_FUNC_END(ffi_closure_trampoline_table_page)
|
||||
#endif
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
ARM_FUNC_START(ffi_arm_trampoline)
|
||||
0: adr ip, 0b
|
||||
stmdb sp!, {r0, ip}
|
||||
ldr pc, 1f
|
||||
1: .long 0
|
||||
ARM_FUNC_END(ffi_arm_trampoline)
|
||||
|
||||
#else
|
||||
|
||||
ARM_FUNC_START(ffi_arm_trampoline, 1)
|
||||
ARM_FUNC_START(ffi_arm_trampoline)
|
||||
0: adr ip, 0b
|
||||
ldr pc, 1f
|
||||
1: .long 0
|
||||
ARM_FUNC_END(ffi_arm_trampoline)
|
||||
|
||||
#endif /* FFI_EXEC_TRAMPOLINE_TABLE */
|
||||
#endif /* __arm__ */
|
||||
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
|
311
libffi/src/arm/sysv_msvc_arm32.S
Normal file
311
libffi/src/arm/sysv_msvc_arm32.S
Normal file
|
@ -0,0 +1,311 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
|
||||
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
|
||||
Copyright (c) 2019 Microsoft Corporation.
|
||||
|
||||
ARM Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
#include "internal.h"
|
||||
#include "ksarm.h"
|
||||
|
||||
|
||||
; 8 byte aligned AREA to support 8 byte aligned jump tables
|
||||
MACRO
|
||||
NESTED_ENTRY_FFI $FuncName, $AreaName, $ExceptHandler
|
||||
|
||||
; compute the function's labels
|
||||
__DeriveFunctionLabels $FuncName
|
||||
|
||||
; determine the area we will put the function into
|
||||
__FuncArea SETS "|.text|"
|
||||
IF "$AreaName" != ""
|
||||
__FuncArea SETS "$AreaName"
|
||||
ENDIF
|
||||
|
||||
; set up the exception handler itself
|
||||
__FuncExceptionHandler SETS ""
|
||||
IF "$ExceptHandler" != ""
|
||||
__FuncExceptionHandler SETS "|$ExceptHandler|"
|
||||
ENDIF
|
||||
|
||||
; switch to the specified area, jump tables require 8 byte alignment
|
||||
AREA $__FuncArea,CODE,CODEALIGN,ALIGN=3,READONLY
|
||||
|
||||
; export the function name
|
||||
__ExportProc $FuncName
|
||||
|
||||
; flush any pending literal pool stuff
|
||||
ROUT
|
||||
|
||||
; reset the state of the unwind code tracking
|
||||
__ResetUnwindState
|
||||
|
||||
MEND
|
||||
|
||||
; MACRO
|
||||
; TABLE_ENTRY $Type, $Table
|
||||
;$Type_$Table
|
||||
; MEND
|
||||
|
||||
#define E(index,table) return_##index##_##table
|
||||
|
||||
; r0: stack
|
||||
; r1: frame
|
||||
; r2: fn
|
||||
; r3: vfp_used
|
||||
|
||||
; fake entry point exists only to generate exists only to
|
||||
; generate .pdata for exception unwinding
|
||||
NESTED_ENTRY_FFI ffi_call_VFP_fake
|
||||
PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
|
||||
|
||||
ALTERNATE_ENTRY ffi_call_VFP
|
||||
cmp r3, #3 ; load only d0 if possible
|
||||
vldrle d0, [r0]
|
||||
vldmgt r0, {d0-d7}
|
||||
add r0, r0, #64 ; discard the vfp register args
|
||||
b ffi_call_SYSV
|
||||
NESTED_END ffi_call_VFP_fake
|
||||
|
||||
; fake entry point exists only to generate exists only to
|
||||
; generate .pdata for exception unwinding
|
||||
NESTED_ENTRY_FFI ffi_call_SYSV_fake
|
||||
PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
|
||||
|
||||
ALTERNATE_ENTRY ffi_call_SYSV
|
||||
stm r1, {fp, lr}
|
||||
mov fp, r1
|
||||
|
||||
mov sp, r0 ; install the stack pointer
|
||||
mov lr, r2 ; move the fn pointer out of the way
|
||||
ldr ip, [fp, #16] ; install the static chain
|
||||
ldmia sp!, {r0-r3} ; move first 4 parameters in registers.
|
||||
blx lr ; call fn
|
||||
|
||||
; Load r2 with the pointer to storage for the return value
|
||||
; Load r3 with the return type code
|
||||
ldr r2, [fp, #8]
|
||||
ldr r3, [fp, #12]
|
||||
|
||||
; Deallocate the stack with the arguments.
|
||||
mov sp, fp
|
||||
|
||||
; Store values stored in registers.
|
||||
ALIGN 8
|
||||
lsl r3, #3
|
||||
add r3, r3, pc
|
||||
add r3, #8
|
||||
mov pc, r3
|
||||
|
||||
|
||||
E(ARM_TYPE_VFP_S, ffi_call)
|
||||
ALIGN 8
|
||||
vstr s0, [r2]
|
||||
pop {fp,pc}
|
||||
E(ARM_TYPE_VFP_D, ffi_call)
|
||||
ALIGN 8
|
||||
vstr d0, [r2]
|
||||
pop {fp,pc}
|
||||
E(ARM_TYPE_VFP_N, ffi_call)
|
||||
ALIGN 8
|
||||
vstm r2, {d0-d3}
|
||||
pop {fp,pc}
|
||||
E(ARM_TYPE_INT64, ffi_call)
|
||||
ALIGN 8
|
||||
str r1, [r2, #4]
|
||||
nop
|
||||
E(ARM_TYPE_INT, ffi_call)
|
||||
ALIGN 8
|
||||
str r0, [r2]
|
||||
pop {fp,pc}
|
||||
E(ARM_TYPE_VOID, ffi_call)
|
||||
ALIGN 8
|
||||
pop {fp,pc}
|
||||
nop
|
||||
E(ARM_TYPE_STRUCT, ffi_call)
|
||||
ALIGN 8
|
||||
cmp r3, #ARM_TYPE_STRUCT
|
||||
pop {fp,pc}
|
||||
NESTED_END ffi_call_SYSV_fake
|
||||
|
||||
IMPORT |ffi_closure_inner_SYSV|
|
||||
/*
|
||||
int ffi_closure_inner_SYSV
|
||||
(
|
||||
cif, ; r0
|
||||
fun, ; r1
|
||||
user_data, ; r2
|
||||
frame ; r3
|
||||
)
|
||||
*/
|
||||
|
||||
NESTED_ENTRY_FFI ffi_go_closure_SYSV
|
||||
stmdb sp!, {r0-r3} ; save argument regs
|
||||
ldr r0, [ip, #4] ; load cif
|
||||
ldr r1, [ip, #8] ; load fun
|
||||
mov r2, ip ; load user_data
|
||||
b ffi_go_closure_SYSV_0
|
||||
NESTED_END ffi_go_closure_SYSV
|
||||
|
||||
; r3: ffi_closure
|
||||
|
||||
; fake entry point exists only to generate exists only to
|
||||
; generate .pdata for exception unwinding
|
||||
NESTED_ENTRY_FFI ffi_closure_SYSV_fake
|
||||
PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
|
||||
ALTERNATE_ENTRY ffi_closure_SYSV
|
||||
ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment)
|
||||
stmdb sp!, {r0-r3} ; save argument regs
|
||||
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; ffi_closure->cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; ffi_closure->fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; ffi_closure->user_data
|
||||
|
||||
ALTERNATE_ENTRY ffi_go_closure_SYSV_0
|
||||
add ip, sp, #16 ; compute entry sp
|
||||
|
||||
sub sp, sp, #64+32 ; allocate frame parameter (sizeof(vfp_space) = 64, sizeof(result) = 32)
|
||||
mov r3, sp ; set frame parameter
|
||||
stmdb sp!, {ip,lr}
|
||||
|
||||
bl ffi_closure_inner_SYSV ; call the Python closure
|
||||
|
||||
; Load values returned in registers.
|
||||
add r2, sp, #64+8 ; address of closure_frame->result
|
||||
bl ffi_closure_ret ; move result to correct register or memory for type
|
||||
|
||||
ldmfd sp!, {ip,lr}
|
||||
mov sp, ip ; restore stack pointer
|
||||
mov pc, lr
|
||||
NESTED_END ffi_closure_SYSV_fake
|
||||
|
||||
IMPORT |ffi_closure_inner_VFP|
|
||||
/*
|
||||
int ffi_closure_inner_VFP
|
||||
(
|
||||
cif, ; r0
|
||||
fun, ; r1
|
||||
user_data, ; r2
|
||||
frame ; r3
|
||||
)
|
||||
*/
|
||||
|
||||
NESTED_ENTRY_FFI ffi_go_closure_VFP
|
||||
stmdb sp!, {r0-r3} ; save argument regs
|
||||
ldr r0, [ip, #4] ; load cif
|
||||
ldr r1, [ip, #8] ; load fun
|
||||
mov r2, ip ; load user_data
|
||||
b ffi_go_closure_VFP_0
|
||||
NESTED_END ffi_go_closure_VFP
|
||||
|
||||
; fake entry point exists only to generate exists only to
|
||||
; generate .pdata for exception unwinding
|
||||
; r3: closure
|
||||
NESTED_ENTRY_FFI ffi_closure_VFP_fake
|
||||
PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
|
||||
|
||||
ALTERNATE_ENTRY ffi_closure_VFP
|
||||
ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment)
|
||||
stmdb sp!, {r0-r3} ; save argument regs
|
||||
|
||||
ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; load cif
|
||||
ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; load fun
|
||||
ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; load user_data
|
||||
|
||||
ALTERNATE_ENTRY ffi_go_closure_VFP_0
|
||||
add ip, sp, #16 ; compute entry sp
|
||||
sub sp, sp, #32 ; save space for closure_frame->result
|
||||
vstmdb sp!, {d0-d7} ; push closure_frame->vfp_space
|
||||
|
||||
mov r3, sp ; save closure_frame
|
||||
stmdb sp!, {ip,lr}
|
||||
|
||||
bl ffi_closure_inner_VFP
|
||||
|
||||
; Load values returned in registers.
|
||||
add r2, sp, #64+8 ; load result
|
||||
bl ffi_closure_ret
|
||||
ldmfd sp!, {ip,lr}
|
||||
mov sp, ip ; restore stack pointer
|
||||
mov pc, lr
|
||||
NESTED_END ffi_closure_VFP_fake
|
||||
|
||||
/* Load values returned in registers for both closure entry points.
|
||||
Note that we use LDM with SP in the register set. This is deprecated
|
||||
by ARM, but not yet unpredictable. */
|
||||
|
||||
NESTED_ENTRY_FFI ffi_closure_ret
|
||||
stmdb sp!, {fp,lr}
|
||||
|
||||
ALIGN 8
|
||||
lsl r0, #3
|
||||
add r0, r0, pc
|
||||
add r0, #8
|
||||
mov pc, r0
|
||||
|
||||
E(ARM_TYPE_VFP_S, ffi_closure)
|
||||
ALIGN 8
|
||||
vldr s0, [r2]
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_VFP_D, ffi_closure)
|
||||
ALIGN 8
|
||||
vldr d0, [r2]
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_VFP_N, ffi_closure)
|
||||
ALIGN 8
|
||||
vldm r2, {d0-d3}
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_INT64, ffi_closure)
|
||||
ALIGN 8
|
||||
ldr r1, [r2, #4]
|
||||
nop
|
||||
E(ARM_TYPE_INT, ffi_closure)
|
||||
ALIGN 8
|
||||
ldr r0, [r2]
|
||||
b call_epilogue
|
||||
E(ARM_TYPE_VOID, ffi_closure)
|
||||
ALIGN 8
|
||||
b call_epilogue
|
||||
nop
|
||||
E(ARM_TYPE_STRUCT, ffi_closure)
|
||||
ALIGN 8
|
||||
b call_epilogue
|
||||
call_epilogue
|
||||
ldmfd sp!, {fp,pc}
|
||||
NESTED_END ffi_closure_ret
|
||||
|
||||
AREA |.trampoline|, DATA, THUMB, READONLY
|
||||
EXPORT |ffi_arm_trampoline|
|
||||
|ffi_arm_trampoline| DATA
|
||||
thisproc adr ip, thisproc
|
||||
stmdb sp!, {ip, r0}
|
||||
ldr pc, [pc, #0]
|
||||
DCD 0
|
||||
;ENDP
|
||||
|
||||
END
|
|
@ -1,5 +1,6 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
closures.c - Copyright (c) 2007, 2009, 2010 Red Hat, Inc.
|
||||
closures.c - Copyright (c) 2019 Anthony Green
|
||||
Copyright (c) 2007, 2009, 2010 Red Hat, Inc.
|
||||
Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc
|
||||
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
|
||||
|
||||
|
@ -30,11 +31,98 @@
|
|||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
#include <tramp.h>
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if __NetBSD_Version__ - 0 >= 799007200
|
||||
/* NetBSD with PROT_MPROTECT */
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_SYS_MEMFD_H
|
||||
#include <sys/memfd.h>
|
||||
#endif
|
||||
|
||||
static const size_t overhead =
|
||||
(sizeof(max_align_t) > sizeof(void *) + sizeof(size_t)) ?
|
||||
sizeof(max_align_t)
|
||||
: sizeof(void *) + sizeof(size_t);
|
||||
|
||||
#define ADD_TO_POINTER(p, d) ((void *)((uintptr_t)(p) + (d)))
|
||||
|
||||
void *
|
||||
ffi_closure_alloc (size_t size, void **code)
|
||||
{
|
||||
static size_t page_size;
|
||||
size_t rounded_size;
|
||||
void *codeseg, *dataseg;
|
||||
int prot;
|
||||
|
||||
/* Expect that PAX mprotect is active and a separate code mapping is necessary. */
|
||||
if (!code)
|
||||
return NULL;
|
||||
|
||||
/* Obtain system page size. */
|
||||
if (!page_size)
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
|
||||
/* Round allocation size up to the next page, keeping in mind the size field and pointer to code map. */
|
||||
rounded_size = (size + overhead + page_size - 1) & ~(page_size - 1);
|
||||
|
||||
/* Primary mapping is RW, but request permission to switch to PROT_EXEC later. */
|
||||
prot = PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC);
|
||||
dataseg = mmap(NULL, rounded_size, prot, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
if (dataseg == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
/* Create secondary mapping and switch it to RX. */
|
||||
codeseg = mremap(dataseg, rounded_size, NULL, rounded_size, MAP_REMAPDUP);
|
||||
if (codeseg == MAP_FAILED) {
|
||||
munmap(dataseg, rounded_size);
|
||||
return NULL;
|
||||
}
|
||||
if (mprotect(codeseg, rounded_size, PROT_READ | PROT_EXEC) == -1) {
|
||||
munmap(codeseg, rounded_size);
|
||||
munmap(dataseg, rounded_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remember allocation size and location of the secondary mapping for ffi_closure_free. */
|
||||
memcpy(dataseg, &rounded_size, sizeof(rounded_size));
|
||||
memcpy(ADD_TO_POINTER(dataseg, sizeof(size_t)), &codeseg, sizeof(void *));
|
||||
*code = ADD_TO_POINTER(codeseg, overhead);
|
||||
return ADD_TO_POINTER(dataseg, overhead);
|
||||
}
|
||||
|
||||
void
|
||||
ffi_closure_free (void *ptr)
|
||||
{
|
||||
void *codeseg, *dataseg;
|
||||
size_t rounded_size;
|
||||
|
||||
dataseg = ADD_TO_POINTER(ptr, -overhead);
|
||||
memcpy(&rounded_size, dataseg, sizeof(rounded_size));
|
||||
memcpy(&codeseg, ADD_TO_POINTER(dataseg, sizeof(size_t)), sizeof(void *));
|
||||
munmap(dataseg, rounded_size);
|
||||
munmap(codeseg, rounded_size);
|
||||
}
|
||||
|
||||
int
|
||||
ffi_tramp_is_present (__attribute__((unused)) void *ptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else /* !NetBSD with PROT_MPROTECT */
|
||||
|
||||
#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
|
||||
# if __gnu_linux__ && !defined(__ANDROID__)
|
||||
# if __linux__ && !defined(__ANDROID__)
|
||||
/* This macro indicates it may be forbidden to map anonymous memory
|
||||
with both write and execute permission. Code compiled when this
|
||||
option is defined will attempt to map such pages once, but if it
|
||||
|
@ -45,7 +133,7 @@
|
|||
# define FFI_MMAP_EXEC_WRIT 1
|
||||
# define HAVE_MNTENT 1
|
||||
# endif
|
||||
# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)
|
||||
# if defined(_WIN32) || defined(__OS2__)
|
||||
/* Windows systems may have Data Execution Protection (DEP) enabled,
|
||||
which requires the use of VirtualMalloc/VirtualFree to alloc/free
|
||||
executable memory. */
|
||||
|
@ -54,7 +142,7 @@
|
|||
#endif
|
||||
|
||||
#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
|
||||
# ifdef __linux__
|
||||
# if defined(__linux__) && !defined(__ANDROID__)
|
||||
/* When defined to 1 check for SELinux and if SELinux is active,
|
||||
don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
|
||||
might cause audit messages. */
|
||||
|
@ -64,11 +152,226 @@
|
|||
|
||||
#if FFI_CLOSURES
|
||||
|
||||
# if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
#if FFI_EXEC_TRAMPOLINE_TABLE
|
||||
|
||||
#ifdef __MACH__
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTRAUTH
|
||||
#include <ptrauth.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void *ffi_closure_trampoline_table_page;
|
||||
|
||||
typedef struct ffi_trampoline_table ffi_trampoline_table;
|
||||
typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
|
||||
|
||||
struct ffi_trampoline_table
|
||||
{
|
||||
/* contiguous writable and executable pages */
|
||||
vm_address_t config_page;
|
||||
|
||||
/* free list tracking */
|
||||
uint16_t free_count;
|
||||
ffi_trampoline_table_entry *free_list;
|
||||
ffi_trampoline_table_entry *free_list_pool;
|
||||
|
||||
ffi_trampoline_table *prev;
|
||||
ffi_trampoline_table *next;
|
||||
};
|
||||
|
||||
struct ffi_trampoline_table_entry
|
||||
{
|
||||
void *(*trampoline) (void);
|
||||
ffi_trampoline_table_entry *next;
|
||||
};
|
||||
|
||||
/* Total number of trampolines that fit in one trampoline table */
|
||||
#define FFI_TRAMPOLINE_COUNT (PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE)
|
||||
|
||||
static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static ffi_trampoline_table *ffi_trampoline_tables = NULL;
|
||||
|
||||
static ffi_trampoline_table *
|
||||
ffi_trampoline_table_alloc (void)
|
||||
{
|
||||
ffi_trampoline_table *table;
|
||||
vm_address_t config_page;
|
||||
vm_address_t trampoline_page;
|
||||
vm_address_t trampoline_page_template;
|
||||
vm_prot_t cur_prot;
|
||||
vm_prot_t max_prot;
|
||||
kern_return_t kt;
|
||||
uint16_t i;
|
||||
|
||||
/* Allocate two pages -- a config page and a placeholder page */
|
||||
config_page = 0x0;
|
||||
kt = vm_allocate (mach_task_self (), &config_page, PAGE_MAX_SIZE * 2,
|
||||
VM_FLAGS_ANYWHERE);
|
||||
if (kt != KERN_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
/* Remap the trampoline table on top of the placeholder page */
|
||||
trampoline_page = config_page + PAGE_MAX_SIZE;
|
||||
|
||||
#ifdef HAVE_PTRAUTH
|
||||
trampoline_page_template = (vm_address_t)(uintptr_t)ptrauth_auth_data((void *)&ffi_closure_trampoline_table_page, ptrauth_key_function_pointer, 0);
|
||||
#else
|
||||
trampoline_page_template = (vm_address_t)&ffi_closure_trampoline_table_page;
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
/* ffi_closure_trampoline_table_page can be thumb-biased on some ARM archs */
|
||||
trampoline_page_template &= ~1UL;
|
||||
#endif
|
||||
kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_MAX_SIZE, 0x0,
|
||||
VM_FLAGS_OVERWRITE, mach_task_self (), trampoline_page_template,
|
||||
FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
|
||||
if (kt != KERN_SUCCESS || !(cur_prot & VM_PROT_EXECUTE))
|
||||
{
|
||||
vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We have valid trampoline and config pages */
|
||||
table = calloc (1, sizeof (ffi_trampoline_table));
|
||||
table->free_count = FFI_TRAMPOLINE_COUNT;
|
||||
table->config_page = config_page;
|
||||
|
||||
/* Create and initialize the free list */
|
||||
table->free_list_pool =
|
||||
calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry));
|
||||
|
||||
for (i = 0; i < table->free_count; i++)
|
||||
{
|
||||
ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
|
||||
entry->trampoline =
|
||||
(void *) (trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
|
||||
#ifdef HAVE_PTRAUTH
|
||||
entry->trampoline = ptrauth_sign_unauthenticated(entry->trampoline, ptrauth_key_function_pointer, 0);
|
||||
#endif
|
||||
|
||||
if (i < table->free_count - 1)
|
||||
entry->next = &table->free_list_pool[i + 1];
|
||||
}
|
||||
|
||||
table->free_list = table->free_list_pool;
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_trampoline_table_free (ffi_trampoline_table *table)
|
||||
{
|
||||
/* Remove from the list */
|
||||
if (table->prev != NULL)
|
||||
table->prev->next = table->next;
|
||||
|
||||
if (table->next != NULL)
|
||||
table->next->prev = table->prev;
|
||||
|
||||
/* Deallocate pages */
|
||||
vm_deallocate (mach_task_self (), table->config_page, PAGE_MAX_SIZE * 2);
|
||||
|
||||
/* Deallocate free list */
|
||||
free (table->free_list_pool);
|
||||
free (table);
|
||||
}
|
||||
|
||||
void *
|
||||
ffi_closure_alloc (size_t size, void **code)
|
||||
{
|
||||
/* Create the closure */
|
||||
ffi_closure *closure = malloc (size);
|
||||
if (closure == NULL)
|
||||
return NULL;
|
||||
|
||||
pthread_mutex_lock (&ffi_trampoline_lock);
|
||||
|
||||
/* Check for an active trampoline table with available entries. */
|
||||
ffi_trampoline_table *table = ffi_trampoline_tables;
|
||||
if (table == NULL || table->free_list == NULL)
|
||||
{
|
||||
table = ffi_trampoline_table_alloc ();
|
||||
if (table == NULL)
|
||||
{
|
||||
pthread_mutex_unlock (&ffi_trampoline_lock);
|
||||
free (closure);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Insert the new table at the top of the list */
|
||||
table->next = ffi_trampoline_tables;
|
||||
if (table->next != NULL)
|
||||
table->next->prev = table;
|
||||
|
||||
ffi_trampoline_tables = table;
|
||||
}
|
||||
|
||||
/* Claim the free entry */
|
||||
ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
|
||||
ffi_trampoline_tables->free_list = entry->next;
|
||||
ffi_trampoline_tables->free_count--;
|
||||
entry->next = NULL;
|
||||
|
||||
pthread_mutex_unlock (&ffi_trampoline_lock);
|
||||
|
||||
/* Initialize the return values */
|
||||
*code = entry->trampoline;
|
||||
closure->trampoline_table = table;
|
||||
closure->trampoline_table_entry = entry;
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
void
|
||||
ffi_closure_free (void *ptr)
|
||||
{
|
||||
ffi_closure *closure = ptr;
|
||||
|
||||
pthread_mutex_lock (&ffi_trampoline_lock);
|
||||
|
||||
/* Fetch the table and entry references */
|
||||
ffi_trampoline_table *table = closure->trampoline_table;
|
||||
ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
|
||||
|
||||
/* Return the entry to the free list */
|
||||
entry->next = table->free_list;
|
||||
table->free_list = entry;
|
||||
table->free_count++;
|
||||
|
||||
/* If all trampolines within this table are free, and at least one other table exists, deallocate
|
||||
* the table */
|
||||
if (table->free_count == FFI_TRAMPOLINE_COUNT
|
||||
&& ffi_trampoline_tables != table)
|
||||
{
|
||||
ffi_trampoline_table_free (table);
|
||||
}
|
||||
else if (ffi_trampoline_tables != table)
|
||||
{
|
||||
/* Otherwise, bump this table to the top of the list */
|
||||
table->prev = NULL;
|
||||
table->next = ffi_trampoline_tables;
|
||||
if (ffi_trampoline_tables != NULL)
|
||||
ffi_trampoline_tables->prev = table;
|
||||
|
||||
ffi_trampoline_tables = table;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&ffi_trampoline_lock);
|
||||
|
||||
/* Free the closure */
|
||||
free (closure);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Per-target implementation; It's unclear what can reasonable be shared between two OS/architecture implementations.
|
||||
|
||||
# elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
|
||||
#elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
|
||||
|
||||
#define USE_LOCKS 1
|
||||
#define USE_DL_PREFIX 1
|
||||
|
@ -94,14 +397,6 @@
|
|||
/* Don't allocate more than a page unless needed. */
|
||||
#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
|
||||
|
||||
#if FFI_CLOSURE_TEST
|
||||
/* Don't release single pages, to avoid a worst-case scenario of
|
||||
continuously allocating and releasing single pages, but release
|
||||
pairs of pages, which should do just as well given that allocations
|
||||
are likely to be small. */
|
||||
#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -111,7 +406,7 @@
|
|||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#if !defined(X86_WIN32) && !defined(X86_WIN64)
|
||||
#if !defined(_WIN32)
|
||||
#ifdef HAVE_MNTENT
|
||||
#include <mntent.h>
|
||||
#endif /* HAVE_MNTENT */
|
||||
|
@ -237,11 +532,11 @@ static int dlmalloc_trim(size_t) MAYBE_UNUSED;
|
|||
static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
|
||||
static void dlmalloc_stats(void) MAYBE_UNUSED;
|
||||
|
||||
#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
|
||||
#if !(defined(_WIN32) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
|
||||
/* Use these for mmap and munmap within dlmalloc.c. */
|
||||
static void *dlmmap(void *, size_t, int, int, int, off_t);
|
||||
static int dlmunmap(void *, size_t);
|
||||
#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
|
||||
#endif /* !(defined(_WIN32) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
|
||||
|
||||
#define mmap dlmmap
|
||||
#define munmap dlmunmap
|
||||
|
@ -251,7 +546,7 @@ static int dlmunmap(void *, size_t);
|
|||
#undef mmap
|
||||
#undef munmap
|
||||
|
||||
#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
|
||||
#if !(defined(_WIN32) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
|
||||
|
||||
/* A mutex used to synchronize access to *exec* variables in this file. */
|
||||
static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
@ -263,6 +558,17 @@ static int execfd = -1;
|
|||
/* The amount of space already allocated from the temporary file. */
|
||||
static size_t execsize = 0;
|
||||
|
||||
#ifdef HAVE_MEMFD_CREATE
|
||||
/* Open a temporary file name, and immediately unlink it. */
|
||||
static int
|
||||
open_temp_exec_file_memfd (const char *name)
|
||||
{
|
||||
int fd;
|
||||
fd = memfd_create (name, MFD_CLOEXEC);
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open a temporary file name, and immediately unlink it. */
|
||||
static int
|
||||
open_temp_exec_file_name (char *name, int flags)
|
||||
|
@ -308,7 +614,7 @@ open_temp_exec_file_dir (const char *dir)
|
|||
}
|
||||
#endif
|
||||
|
||||
lendir = strlen (dir);
|
||||
lendir = (int) strlen (dir);
|
||||
tempname = __builtin_alloca (lendir + sizeof (suffix));
|
||||
|
||||
if (!tempname)
|
||||
|
@ -390,6 +696,10 @@ static struct
|
|||
const char *arg;
|
||||
int repeat;
|
||||
} open_temp_exec_file_opts[] = {
|
||||
#ifdef HAVE_MEMFD_CREATE
|
||||
{ open_temp_exec_file_memfd, "libffi", 0 },
|
||||
#endif
|
||||
{ open_temp_exec_file_env, "LIBFFI_TMPDIR", 0 },
|
||||
{ open_temp_exec_file_env, "TMPDIR", 0 },
|
||||
{ open_temp_exec_file_dir, "/tmp", 0 },
|
||||
{ open_temp_exec_file_dir, "/var/tmp", 0 },
|
||||
|
@ -449,6 +759,36 @@ open_temp_exec_file (void)
|
|||
return fd;
|
||||
}
|
||||
|
||||
/* We need to allocate space in a file that will be backing a writable
|
||||
mapping. Several problems exist with the usual approaches:
|
||||
- fallocate() is Linux-only
|
||||
- posix_fallocate() is not available on all platforms
|
||||
- ftruncate() does not allocate space on filesystems with sparse files
|
||||
Failure to allocate the space will cause SIGBUS to be thrown when
|
||||
the mapping is subsequently written to. */
|
||||
static int
|
||||
allocate_space (int fd, off_t offset, off_t len)
|
||||
{
|
||||
static size_t page_size;
|
||||
|
||||
/* Obtain system page size. */
|
||||
if (!page_size)
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
|
||||
unsigned char buf[page_size];
|
||||
memset (buf, 0, page_size);
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
off_t to_write = (len < page_size) ? len : page_size;
|
||||
if (write (fd, buf, to_write) < to_write)
|
||||
return -1;
|
||||
len -= to_write;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Map in a chunk of memory from the temporary exec file into separate
|
||||
locations in the virtual memory address space, one writable and one
|
||||
executable. Returns the address of the writable portion, after
|
||||
|
@ -470,7 +810,7 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
|
|||
|
||||
offset = execsize;
|
||||
|
||||
if (ftruncate (execfd, offset + length))
|
||||
if (allocate_space (execfd, offset, length))
|
||||
return MFAIL;
|
||||
|
||||
flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
|
||||
|
@ -485,7 +825,13 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
|
|||
close (execfd);
|
||||
goto retry_open;
|
||||
}
|
||||
ftruncate (execfd, offset);
|
||||
if (ftruncate (execfd, offset) != 0)
|
||||
{
|
||||
/* Fixme : Error logs can be added here. Returning an error for
|
||||
* ftruncte() will not add any advantage as it is being
|
||||
* validating in the error case. */
|
||||
}
|
||||
|
||||
return MFAIL;
|
||||
}
|
||||
else if (!offset
|
||||
|
@ -497,7 +843,12 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
|
|||
if (start == MFAIL)
|
||||
{
|
||||
munmap (ptr, length);
|
||||
ftruncate (execfd, offset);
|
||||
if (ftruncate (execfd, offset) != 0)
|
||||
{
|
||||
/* Fixme : Error logs can be added here. Returning an error for
|
||||
* ftruncte() will not add any advantage as it is being
|
||||
* validating in the error case. */
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
|
@ -521,9 +872,11 @@ dlmmap (void *start, size_t length, int prot,
|
|||
&& flags == (MAP_PRIVATE | MAP_ANONYMOUS)
|
||||
&& fd == -1 && offset == 0);
|
||||
|
||||
#if FFI_CLOSURE_TEST
|
||||
printf ("mapping in %zi\n", length);
|
||||
#endif
|
||||
if (execfd == -1 && ffi_tramp_is_supported ())
|
||||
{
|
||||
ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
if (execfd == -1 && is_emutramp_enabled ())
|
||||
{
|
||||
|
@ -570,10 +923,6 @@ dlmunmap (void *start, size_t length)
|
|||
msegmentptr seg = segment_holding (gm, start);
|
||||
void *code;
|
||||
|
||||
#if FFI_CLOSURE_TEST
|
||||
printf ("unmapping %zi\n", length);
|
||||
#endif
|
||||
|
||||
if (seg && (code = add_segment_exec_offset (start, seg)) != start)
|
||||
{
|
||||
int ret = munmap (code, length);
|
||||
|
@ -600,7 +949,7 @@ segment_holding_code (mstate m, char* addr)
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
|
||||
#endif /* !(defined(_WIN32) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
|
||||
|
||||
/* Allocate a chunk of memory with the given size. Returns a pointer
|
||||
to the writable address, and sets *CODE to the executable
|
||||
|
@ -608,23 +957,52 @@ segment_holding_code (mstate m, char* addr)
|
|||
void *
|
||||
ffi_closure_alloc (size_t size, void **code)
|
||||
{
|
||||
void *ptr;
|
||||
void *ptr, *ftramp;
|
||||
|
||||
if (!code)
|
||||
return NULL;
|
||||
|
||||
ptr = dlmalloc (size);
|
||||
ptr = FFI_CLOSURE_PTR (dlmalloc (size));
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
msegmentptr seg = segment_holding (gm, ptr);
|
||||
|
||||
*code = add_segment_exec_offset (ptr, seg);
|
||||
if (!ffi_tramp_is_supported ())
|
||||
return ptr;
|
||||
|
||||
ftramp = ffi_tramp_alloc (0);
|
||||
if (ftramp == NULL)
|
||||
{
|
||||
dlfree (FFI_RESTORE_PTR (ptr));
|
||||
return NULL;
|
||||
}
|
||||
*code = ffi_tramp_get_addr (ftramp);
|
||||
((ffi_closure *) ptr)->ftramp = ftramp;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
ffi_data_to_code_pointer (void *data)
|
||||
{
|
||||
msegmentptr seg = segment_holding (gm, data);
|
||||
/* We expect closures to be allocated with ffi_closure_alloc(), in
|
||||
which case seg will be non-NULL. However, some users take on the
|
||||
burden of managing this memory themselves, in which case this
|
||||
we'll just return data. */
|
||||
if (seg)
|
||||
{
|
||||
if (!ffi_tramp_is_supported ())
|
||||
return add_segment_exec_offset (data, seg);
|
||||
return ffi_tramp_get_addr (((ffi_closure *) data)->ftramp);
|
||||
}
|
||||
else
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Release a chunk of memory allocated with ffi_closure_alloc. If
|
||||
FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
|
||||
writable or the executable address given. Otherwise, only the
|
||||
|
@ -638,30 +1016,19 @@ ffi_closure_free (void *ptr)
|
|||
if (seg)
|
||||
ptr = sub_segment_exec_offset (ptr, seg);
|
||||
#endif
|
||||
if (ffi_tramp_is_supported ())
|
||||
ffi_tramp_free (((ffi_closure *) ptr)->ftramp);
|
||||
|
||||
dlfree (ptr);
|
||||
dlfree (FFI_RESTORE_PTR (ptr));
|
||||
}
|
||||
|
||||
|
||||
#if FFI_CLOSURE_TEST
|
||||
/* Do some internal sanity testing to make sure allocation and
|
||||
deallocation of pages are working as intended. */
|
||||
int main ()
|
||||
int
|
||||
ffi_tramp_is_present (void *ptr)
|
||||
{
|
||||
void *p[3];
|
||||
#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
|
||||
#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
|
||||
GET (0, malloc_getpagesize / 2);
|
||||
GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
|
||||
PUT (1);
|
||||
GET (1, 2 * malloc_getpagesize);
|
||||
GET (2, malloc_getpagesize / 2);
|
||||
PUT (1);
|
||||
PUT (0);
|
||||
PUT (2);
|
||||
return 0;
|
||||
msegmentptr seg = segment_holding (gm, ptr);
|
||||
return seg != NULL && ffi_tramp_is_supported();
|
||||
}
|
||||
#endif /* FFI_CLOSURE_TEST */
|
||||
|
||||
# else /* ! FFI_MMAP_EXEC_WRIT */
|
||||
|
||||
/* On many systems, memory returned by malloc is writable and
|
||||
|
@ -675,14 +1042,28 @@ ffi_closure_alloc (size_t size, void **code)
|
|||
if (!code)
|
||||
return NULL;
|
||||
|
||||
return *code = malloc (size);
|
||||
return *code = FFI_CLOSURE_PTR (malloc (size));
|
||||
}
|
||||
|
||||
void
|
||||
ffi_closure_free (void *ptr)
|
||||
{
|
||||
free (ptr);
|
||||
free (FFI_RESTORE_PTR (ptr));
|
||||
}
|
||||
|
||||
void *
|
||||
ffi_data_to_code_pointer (void *data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
int
|
||||
ffi_tramp_is_present (__attribute__((unused)) void *ptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif /* ! FFI_MMAP_EXEC_WRIT */
|
||||
#endif /* FFI_CLOSURES */
|
||||
|
||||
#endif /* NetBSD with PROT_MPROTECT */
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
|
||||
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
|
||||
#define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG)
|
||||
|
||||
static ffi_status
|
||||
initialize_aggregate_packed_struct (ffi_type * arg)
|
||||
|
@ -190,7 +190,7 @@ ffi_prep_cif_core (ffi_cif * cif,
|
|||
FFI_ASSERT_VALID_TYPE (*ptr);
|
||||
|
||||
if (((*ptr)->alignment - 1) & bytes)
|
||||
bytes = ALIGN (bytes, (*ptr)->alignment);
|
||||
bytes = FFI_ALIGN (bytes, (*ptr)->alignment);
|
||||
if ((*ptr)->type == FFI_TYPE_STRUCT)
|
||||
{
|
||||
if ((*ptr)->size > 8)
|
||||
|
|
395
libffi/src/csky/ffi.c
Normal file
395
libffi/src/csky/ffi.c
Normal file
|
@ -0,0 +1,395 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi.c
|
||||
|
||||
CSKY Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* 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)
|
||||
{
|
||||
register unsigned int i;
|
||||
register void **p_argv;
|
||||
register char *argp;
|
||||
register ffi_type **p_arg;
|
||||
|
||||
argp = stack;
|
||||
|
||||
if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
|
||||
*(void **) argp = ecif->rvalue;
|
||||
argp += 4;
|
||||
}
|
||||
|
||||
p_argv = ecif->avalue;
|
||||
|
||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
||||
(i != 0);
|
||||
i--, p_arg++)
|
||||
{
|
||||
size_t z;
|
||||
size_t alignment;
|
||||
|
||||
/* Align if necessary */
|
||||
alignment = (*p_arg)->alignment;
|
||||
#ifdef __CSKYABIV1__
|
||||
/*
|
||||
* Adapt ABIV1 bug.
|
||||
* If struct's size is larger than 8 bytes, then it always alignment as 4 bytes.
|
||||
*/
|
||||
if (((*p_arg)->type == FFI_TYPE_STRUCT) && ((*p_arg)->size > 8) && (alignment == 8)) {
|
||||
alignment = 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((alignment - 1) & (unsigned) argp) {
|
||||
argp = (char *) FFI_ALIGN(argp, alignment);
|
||||
}
|
||||
|
||||
if ((*p_arg)->type == FFI_TYPE_STRUCT)
|
||||
argp = (char *) FFI_ALIGN(argp, 4);
|
||||
|
||||
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:
|
||||
#ifdef __CSKYBE__
|
||||
memcpy((argp + 4 - (*p_arg)->size), *p_argv, (*p_arg)->size);
|
||||
#else
|
||||
memcpy(argp, *p_argv, (*p_arg)->size);
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
/* Round the stack up to a multiple of 8 bytes. This isn't needed
|
||||
everywhere, but it is on some platforms, and it doesn't hcsky anything
|
||||
when it isn't needed. */
|
||||
cif->bytes = (cif->bytes + 7) & ~7;
|
||||
|
||||
/* Set the return type flag */
|
||||
switch (cif->rtype->type)
|
||||
{
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
cif->flags = (unsigned) FFI_TYPE_SINT64;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
if (cif->rtype->size <= 4)
|
||||
/* A Composite Type not larger than 4 bytes is returned in r0. */
|
||||
cif->flags = (unsigned)FFI_TYPE_INT;
|
||||
else if (cif->rtype->size <= 8)
|
||||
/* A Composite Type not larger than 8 bytes is returned in r0, r1. */
|
||||
cif->flags = (unsigned)FFI_TYPE_SINT64;
|
||||
else
|
||||
/* A Composite Type larger than 8 bytes, or whose size cannot
|
||||
be determined statically ... is stored in memory at an
|
||||
address passed [in r0]. */
|
||||
cif->flags = (unsigned)FFI_TYPE_STRUCT;
|
||||
break;
|
||||
|
||||
default:
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
break;
|
||||
}
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing for variadic calls */
|
||||
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs)
|
||||
{
|
||||
return ffi_prep_cif_machdep(cif);
|
||||
}
|
||||
|
||||
/* Prototypes for assembly functions, in sysv.S */
|
||||
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
|
||||
|
||||
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
extended_cif ecif;
|
||||
|
||||
int small_struct = (cif->flags == FFI_TYPE_INT
|
||||
&& cif->rtype->type == FFI_TYPE_STRUCT);
|
||||
|
||||
ecif.cif = cif;
|
||||
ecif.avalue = avalue;
|
||||
|
||||
unsigned int temp;
|
||||
|
||||
/* If the return value is a struct and we don't have a return */
|
||||
/* value address then we need to make one */
|
||||
|
||||
if ((rvalue == NULL) &&
|
||||
(cif->flags == FFI_TYPE_STRUCT))
|
||||
{
|
||||
ecif.rvalue = alloca(cif->rtype->size);
|
||||
}
|
||||
else if (small_struct)
|
||||
ecif.rvalue = &temp;
|
||||
else
|
||||
ecif.rvalue = rvalue;
|
||||
|
||||
switch (cif->abi)
|
||||
{
|
||||
case FFI_SYSV:
|
||||
ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
|
||||
break;
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
if (small_struct)
|
||||
#ifdef __CSKYBE__
|
||||
memcpy (rvalue, ((unsigned char *)&temp + (4 - cif->rtype->size)), cif->rtype->size);
|
||||
#else
|
||||
memcpy (rvalue, &temp, cif->rtype->size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** private members **/
|
||||
|
||||
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
|
||||
void** args, ffi_cif* cif);
|
||||
|
||||
void ffi_closure_SYSV (ffi_closure *);
|
||||
|
||||
/* This function is jumped to by the trampoline */
|
||||
|
||||
unsigned int
|
||||
ffi_closure_SYSV_inner (closure, respp, args)
|
||||
ffi_closure *closure;
|
||||
void **respp;
|
||||
void *args;
|
||||
{
|
||||
// our various things...
|
||||
ffi_cif *cif;
|
||||
void **arg_area;
|
||||
|
||||
cif = closure->cif;
|
||||
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
||||
|
||||
/* this call will initialize ARG_AREA, such that each
|
||||
* element in that array points to the corresponding
|
||||
* value on the stack; and if the function returns
|
||||
* a structure, it will re-set RESP to point to the
|
||||
* structure return address. */
|
||||
|
||||
ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
|
||||
|
||||
(closure->fun) (cif, *respp, arg_area, closure->user_data);
|
||||
|
||||
#ifdef __CSKYBE__
|
||||
if (cif->flags == FFI_TYPE_INT && cif->rtype->type == FFI_TYPE_STRUCT) {
|
||||
unsigned int tmp = 0;
|
||||
tmp = *(unsigned int *)(*respp);
|
||||
*(unsigned int *)(*respp) = (tmp >> ((4 - cif->rtype->size) * 8));
|
||||
}
|
||||
#endif
|
||||
|
||||
return cif->flags;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
||||
void **avalue, ffi_cif *cif)
|
||||
{
|
||||
register unsigned int i;
|
||||
register void **p_argv;
|
||||
register char *argp;
|
||||
register ffi_type **p_arg;
|
||||
|
||||
argp = stack;
|
||||
|
||||
if ( cif->flags == FFI_TYPE_STRUCT ) {
|
||||
*rvalue = *(void **) argp;
|
||||
argp += 4;
|
||||
}
|
||||
|
||||
p_argv = avalue;
|
||||
|
||||
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
|
||||
{
|
||||
size_t z;
|
||||
size_t alignment;
|
||||
|
||||
alignment = (*p_arg)->alignment;
|
||||
if (alignment < 4)
|
||||
alignment = 4;
|
||||
|
||||
#ifdef __CSKYABIV1__
|
||||
/*
|
||||
* Adapt ABIV1 bug.
|
||||
* If struct's size is larger than 8 bytes, then it always alignment as 4 bytes.
|
||||
*/
|
||||
if (((*p_arg)->type == FFI_TYPE_STRUCT) && ((*p_arg)->size > 8) && (alignment == 8)) {
|
||||
alignment = 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Align if necessary */
|
||||
if ((alignment - 1) & (unsigned) argp) {
|
||||
argp = (char *) FFI_ALIGN(argp, alignment);
|
||||
}
|
||||
|
||||
z = (*p_arg)->size;
|
||||
|
||||
#ifdef __CSKYBE__
|
||||
unsigned int tmp = 0;
|
||||
if ((*p_arg)->size < 4) {
|
||||
tmp = *(unsigned int *)argp;
|
||||
memcpy(argp, ((unsigned char *)&tmp + (4 - (*p_arg)->size)), (*p_arg)->size);
|
||||
}
|
||||
#else
|
||||
/* because we're little endian, this is what it turns into. */
|
||||
#endif
|
||||
*p_argv = (void*) argp;
|
||||
|
||||
p_argv++;
|
||||
argp += z;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* How to make a trampoline. */
|
||||
|
||||
extern unsigned char ffi_csky_trampoline[TRAMPOLINE_SIZE];
|
||||
|
||||
/*
|
||||
* Since there is no __clear_cache in libgcc in csky toolchain.
|
||||
* define ffi_csky_cacheflush in sysv.S.
|
||||
* void ffi_csky_cacheflush(uint32 start_addr, uint32 size, int cache)
|
||||
*/
|
||||
#define CACHEFLUSH_IN_FFI 1
|
||||
#if CACHEFLUSH_IN_FFI
|
||||
extern void ffi_csky_cacheflush(unsigned char *__tramp, unsigned int k,
|
||||
int i);
|
||||
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
|
||||
({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
|
||||
unsigned int __fun = (unsigned int)(FUN); \
|
||||
unsigned int __ctx = (unsigned int)(CTX); \
|
||||
unsigned char *insns = (unsigned char *)(CTX); \
|
||||
memcpy (__tramp, ffi_csky_trampoline, TRAMPOLINE_SIZE); \
|
||||
*(unsigned int*) &__tramp[TRAMPOLINE_SIZE] = __ctx; \
|
||||
*(unsigned int*) &__tramp[TRAMPOLINE_SIZE + 4] = __fun; \
|
||||
ffi_csky_cacheflush(&__tramp[0], TRAMPOLINE_SIZE, 3); /* Clear data mapping. */ \
|
||||
ffi_csky_cacheflush(insns, TRAMPOLINE_SIZE, 3); \
|
||||
/* Clear instruction \
|
||||
mapping. */ \
|
||||
})
|
||||
#else
|
||||
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
|
||||
({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
|
||||
unsigned int __fun = (unsigned int)(FUN); \
|
||||
unsigned int __ctx = (unsigned int)(CTX); \
|
||||
unsigned char *insns = (unsigned char *)(CTX); \
|
||||
memcpy (__tramp, ffi_csky_trampoline, TRAMPOLINE_SIZE); \
|
||||
*(unsigned int*) &__tramp[TRAMPOLINE_SIZE] = __ctx; \
|
||||
*(unsigned int*) &__tramp[TRAMPOLINE_SIZE + 4] = __fun; \
|
||||
__clear_cache((&__tramp[0]), (&__tramp[TRAMPOLINE_SIZE-1])); /* Clear data mapping. */ \
|
||||
__clear_cache(insns, insns + TRAMPOLINE_SIZE); \
|
||||
/* Clear instruction \
|
||||
mapping. */ \
|
||||
})
|
||||
#endif
|
||||
|
||||
/* the cif must already be prep'ed */
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
void (*closure_func)(ffi_closure*) = NULL;
|
||||
|
||||
if (cif->abi == FFI_SYSV)
|
||||
closure_func = &ffi_closure_SYSV;
|
||||
else
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
|
||||
closure_func, \
|
||||
codeloc);
|
||||
|
||||
closure->cif = cif;
|
||||
closure->user_data = user_data;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
|
63
libffi/src/csky/ffitarget.h
Normal file
63
libffi/src/csky/ffitarget.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* -----------------------------------------------------------------*-C-*-
|
||||
ffitarget.h - Copyright (c) 2012 Anthony Green
|
||||
Copyright (c) 2010 CodeSourcery
|
||||
Copyright (c) 1996-2003 Red Hat, Inc.
|
||||
|
||||
Target configuration macros for CSKY.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef LIBFFI_TARGET_H
|
||||
#define LIBFFI_TARGET_H
|
||||
|
||||
#ifndef LIBFFI_H
|
||||
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
|
||||
#endif
|
||||
|
||||
#ifndef LIBFFI_ASM
|
||||
typedef unsigned long ffi_arg;
|
||||
typedef signed long ffi_sarg;
|
||||
|
||||
typedef enum ffi_abi {
|
||||
FFI_FIRST_ABI = 0,
|
||||
FFI_SYSV,
|
||||
FFI_LAST_ABI,
|
||||
FFI_DEFAULT_ABI = FFI_SYSV,
|
||||
} ffi_abi;
|
||||
#endif
|
||||
|
||||
#ifdef __CSKYABIV2__
|
||||
#define FFI_ASM_ARGREG_SIZE 16
|
||||
#define TRAMPOLINE_SIZE 16
|
||||
#define FFI_TRAMPOLINE_SIZE 24
|
||||
#else
|
||||
#define FFI_ASM_ARGREG_SIZE 24
|
||||
#define TRAMPOLINE_SIZE 20
|
||||
#define FFI_TRAMPOLINE_SIZE 28
|
||||
#endif
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
#endif
|
371
libffi/src/csky/sysv.S
Normal file
371
libffi/src/csky/sysv.S
Normal file
|
@ -0,0 +1,371 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
sysv.S
|
||||
|
||||
CSKY Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
||||
.macro CSKY_FUNC_START name
|
||||
.text
|
||||
.align 2
|
||||
.globl \name
|
||||
.type \name, @function
|
||||
\name:
|
||||
.endm
|
||||
|
||||
#ifdef __CSKYABIV2__
|
||||
|
||||
/*
|
||||
* a0: fn
|
||||
* a1: &ecif
|
||||
* a2: cif->bytes
|
||||
* a3: fig->flags
|
||||
* sp+0: ecif.rvalue
|
||||
*/
|
||||
CSKY_FUNC_START ffi_call_SYSV
|
||||
/* Save registers */
|
||||
.cfi_startproc
|
||||
subi sp, 28
|
||||
.cfi_def_cfa_offset 28
|
||||
stw a0, (sp, 0x0)
|
||||
.cfi_offset 0, -28
|
||||
stw a1, (sp, 0x4)
|
||||
.cfi_offset 1, -24
|
||||
stw a2, (sp, 0x8)
|
||||
.cfi_offset 2, -20
|
||||
stw a3, (sp, 0xC)
|
||||
.cfi_offset 3, -16
|
||||
stw l0, (sp, 0x10)
|
||||
.cfi_offset 4, -12
|
||||
stw l1, (sp, 0x14)
|
||||
.cfi_offset 5, -8
|
||||
stw lr, (sp, 0x18)
|
||||
.cfi_offset 15, -4
|
||||
|
||||
mov l0, sp
|
||||
.cfi_def_cfa_register 4
|
||||
|
||||
/* Make room for all of the new args. */
|
||||
subu sp, sp, a2
|
||||
|
||||
/* Place all of the ffi_prep_args in position */
|
||||
mov a0, sp
|
||||
/* a1 already set */
|
||||
|
||||
/* Call ffi_prep_args(stack, &ecif) */
|
||||
jsri ffi_prep_args
|
||||
|
||||
/* move first 4 parameters in registers */
|
||||
ldw a0, (sp, 0x0)
|
||||
ldw a1, (sp, 0x4)
|
||||
ldw a2, (sp, 0x8)
|
||||
ldw a3, (sp, 0xC)
|
||||
|
||||
/* and adjust stack */
|
||||
subu lr, l0, sp /* cif->bytes == l0 - sp */
|
||||
cmphsi lr, 16
|
||||
movi l1, 16
|
||||
movt lr, l1
|
||||
addu sp, sp, lr
|
||||
|
||||
ldw l1, (l0, 0) /* load fn() in advance */
|
||||
|
||||
/* call (fn) (...) */
|
||||
jsr l1
|
||||
|
||||
/* Remove the space we pushed for the args */
|
||||
mov sp, l0
|
||||
|
||||
/* Load r2 with the pointer to storage for the return value */
|
||||
ldw a2, (sp, 0x1C)
|
||||
|
||||
/* Load r3 with the return type code */
|
||||
ldw a3, (sp, 0xC)
|
||||
|
||||
/* If the return value pointer is NULL, assume no return value. */
|
||||
cmpnei a2, 0
|
||||
bf .Lepilogue
|
||||
|
||||
cmpnei a3, FFI_TYPE_STRUCT
|
||||
bf .Lepilogue
|
||||
|
||||
/* return INT64 */
|
||||
cmpnei a3, FFI_TYPE_SINT64
|
||||
bt .Lretint
|
||||
/* stw a0, (a2, 0x0) at .Lretint */
|
||||
stw a1, (a2, 0x4)
|
||||
|
||||
.Lretint:
|
||||
/* return INT */
|
||||
stw a0, (a2, 0x0)
|
||||
|
||||
.Lepilogue:
|
||||
ldw a0, (sp, 0x0)
|
||||
ldw a1, (sp, 0x4)
|
||||
ldw a2, (sp, 0x8)
|
||||
ldw a3, (sp, 0xC)
|
||||
ldw l0, (sp, 0x10)
|
||||
ldw l1, (sp, 0x14)
|
||||
ldw lr, (sp, 0x18)
|
||||
addi sp, sp, 28
|
||||
rts
|
||||
.cfi_endproc
|
||||
.size ffi_call_SYSV, .-ffi_call_SYSV
|
||||
|
||||
|
||||
/*
|
||||
* unsigned int FFI_HIDDEN
|
||||
* ffi_closure_SYSV_inner (closure, respp, args)
|
||||
* ffi_closure *closure;
|
||||
* void **respp;
|
||||
* void *args;
|
||||
*/
|
||||
CSKY_FUNC_START ffi_closure_SYSV
|
||||
.cfi_startproc
|
||||
mov a2, sp
|
||||
addi a1, sp, 16
|
||||
subi sp, sp, 24
|
||||
.cfi_def_cfa_offset 40
|
||||
stw a1, (sp, 0x10)
|
||||
.cfi_offset 1, -24
|
||||
stw lr, (sp, 0x14)
|
||||
.cfi_offset 15, -20
|
||||
stw sp, (sp, 0x8)
|
||||
addi a1, sp, 8
|
||||
jsri ffi_closure_SYSV_inner
|
||||
ldw a0, (sp, 0x0)
|
||||
/*
|
||||
* if FFI_TYPE_SINT64, need a1.
|
||||
* if FFI_TYPE_INT, ignore a1.
|
||||
*/
|
||||
ldw a1, (sp, 0x4)
|
||||
|
||||
ldw lr, (sp, 0x14)
|
||||
addi sp, sp, 40
|
||||
rts
|
||||
.cfi_endproc
|
||||
.size ffi_closure_SYSV, .-ffi_closure_SYSV
|
||||
|
||||
CSKY_FUNC_START ffi_csky_trampoline
|
||||
subi sp, sp, 16
|
||||
stw a0, (sp, 0x0)
|
||||
stw a1, (sp, 0x4)
|
||||
stw a2, (sp, 0x8)
|
||||
stw a3, (sp, 0xC)
|
||||
lrw a0, [.Lctx]
|
||||
lrw a1, [.Lfun]
|
||||
jmp a1
|
||||
.Lctx:
|
||||
mov a0, a0
|
||||
mov a0, a0
|
||||
.Lfun:
|
||||
|
||||
.size ffi_csky_trampoline, .-ffi_csky_trampoline
|
||||
|
||||
CSKY_FUNC_START ffi_csky_cacheflush
|
||||
mov t0, r7
|
||||
movi r7, 123
|
||||
trap 0
|
||||
mov r7, t0
|
||||
rts
|
||||
|
||||
.size ffi_csky_cacheflush, .-ffi_csky_cacheflush
|
||||
|
||||
#else /* !__CSKYABIV2__ */
|
||||
|
||||
/*
|
||||
* a0: fn
|
||||
* a1: &ecif
|
||||
* a2: cif->bytes
|
||||
* a3: fig->flags
|
||||
* a4: ecif.rvalue
|
||||
*/
|
||||
CSKY_FUNC_START ffi_call_SYSV
|
||||
/* Save registers */
|
||||
.cfi_startproc
|
||||
subi sp, 32
|
||||
subi sp, 8
|
||||
.cfi_def_cfa_offset 40
|
||||
stw a0, (sp, 0x0)
|
||||
.cfi_offset 2, -40
|
||||
stw a1, (sp, 0x4)
|
||||
.cfi_offset 3, -36
|
||||
stw a2, (sp, 0x8)
|
||||
.cfi_offset 4, -32
|
||||
stw a3, (sp, 0xC)
|
||||
.cfi_offset 5, -28
|
||||
stw a4, (sp, 0x10)
|
||||
.cfi_offset 6, -24
|
||||
stw a5, (sp, 0x14)
|
||||
.cfi_offset 7, -20
|
||||
stw l0, (sp, 0x18)
|
||||
.cfi_offset 8, -16
|
||||
stw l1, (sp, 0x1C)
|
||||
.cfi_offset 9, -12
|
||||
stw lr, (sp, 0x20)
|
||||
.cfi_offset 15, -8
|
||||
|
||||
mov l0, sp
|
||||
.cfi_def_cfa_register 8
|
||||
|
||||
/* Make room for all of the new args. */
|
||||
subu sp, sp, a2
|
||||
|
||||
/* Place all of the ffi_prep_args in position */
|
||||
mov a0, sp
|
||||
/* a1 already set */
|
||||
|
||||
/* Call ffi_prep_args(stack, &ecif) */
|
||||
jsri ffi_prep_args
|
||||
|
||||
/* move first 4 parameters in registers */
|
||||
ldw a0, (sp, 0x0)
|
||||
ldw a1, (sp, 0x4)
|
||||
ldw a2, (sp, 0x8)
|
||||
ldw a3, (sp, 0xC)
|
||||
ldw a4, (sp, 0x10)
|
||||
ldw a5, (sp, 0x14)
|
||||
|
||||
/* and adjust stack */
|
||||
mov lr, l0
|
||||
subu lr, sp /* cif->bytes == l0 - sp */
|
||||
movi l1, 24
|
||||
cmphs lr, l1
|
||||
movt lr, l1
|
||||
addu sp, sp, lr
|
||||
|
||||
ldw l1, (l0, 0) /* load fn() in advance */
|
||||
|
||||
/* call (fn) (...) */
|
||||
jsr l1
|
||||
|
||||
/* Remove the space we pushed for the args */
|
||||
mov sp, l0
|
||||
|
||||
/* Load r2 with the pointer to storage for the return value */
|
||||
ldw a2, (sp, 0x10)
|
||||
|
||||
/* Load r3 with the return type code */
|
||||
ldw a3, (sp, 0xC)
|
||||
|
||||
/* If the return value pointer is NULL, assume no return value. */
|
||||
cmpnei a2, 0
|
||||
bf .Lepilogue
|
||||
|
||||
cmpnei a3, FFI_TYPE_STRUCT
|
||||
bf .Lepilogue
|
||||
|
||||
/* return INT64 */
|
||||
cmpnei a3, FFI_TYPE_SINT64
|
||||
bt .Lretint
|
||||
/* stw a0, (a2, 0x0) at .Lretint */
|
||||
stw a1, (a2, 0x4)
|
||||
|
||||
.Lretint:
|
||||
/* return INT */
|
||||
stw a0, (a2, 0x0)
|
||||
|
||||
.Lepilogue:
|
||||
ldw a0, (sp, 0x0)
|
||||
ldw a1, (sp, 0x4)
|
||||
ldw a2, (sp, 0x8)
|
||||
ldw a3, (sp, 0xC)
|
||||
ldw a4, (sp, 0x10)
|
||||
ldw a5, (sp, 0x14)
|
||||
ldw l0, (sp, 0x18)
|
||||
ldw l1, (sp, 0x1C)
|
||||
ldw lr, (sp, 0x20)
|
||||
addi sp, sp, 32
|
||||
addi sp, sp, 8
|
||||
rts
|
||||
.cfi_endproc
|
||||
|
||||
.size ffi_call_SYSV, .-ffi_call_SYSV
|
||||
|
||||
|
||||
/*
|
||||
* unsigned int FFI_HIDDEN
|
||||
* ffi_closure_SYSV_inner (closure, respp, args)
|
||||
* ffi_closure *closure;
|
||||
* void **respp;
|
||||
* void *args;
|
||||
*/
|
||||
CSKY_FUNC_START ffi_closure_SYSV
|
||||
.cfi_startproc
|
||||
mov a2, sp
|
||||
mov a1, sp
|
||||
addi a1, 24
|
||||
subi sp, sp, 24
|
||||
.cfi_def_cfa_offset 48
|
||||
stw a1, (sp, 0x10)
|
||||
.cfi_offset 3, -32
|
||||
stw lr, (sp, 0x14)
|
||||
.cfi_offset 15, -28
|
||||
stw sp, (sp, 0x8)
|
||||
mov a1, sp
|
||||
addi a1, 8
|
||||
jsri ffi_closure_SYSV_inner
|
||||
ldw a0, (sp, 0x0)
|
||||
/*
|
||||
* if FFI_TYPE_SINT64, need a1.
|
||||
* if FFI_TYPE_INT, ignore a1.
|
||||
*/
|
||||
ldw a1, (sp, 0x4)
|
||||
|
||||
ldw lr, (sp, 0x14)
|
||||
addi sp, sp, 24
|
||||
addi sp, sp, 24
|
||||
rts
|
||||
.cfi_endproc
|
||||
|
||||
.size ffi_closure_SYSV, .-ffi_closure_SYSV
|
||||
|
||||
CSKY_FUNC_START ffi_csky_trampoline
|
||||
subi sp, 24
|
||||
stw a0, (sp, 0x0)
|
||||
stw a1, (sp, 0x4)
|
||||
stw a2, (sp, 0x8)
|
||||
stw a3, (sp, 0xC)
|
||||
stw a4, (sp, 0x10)
|
||||
stw a5, (sp, 0x14)
|
||||
lrw a0, [.Lctx]
|
||||
lrw a1, [.Lfun]
|
||||
jmp a1
|
||||
.Lctx:
|
||||
mov a0, a0
|
||||
mov a0, a0
|
||||
.Lfun:
|
||||
|
||||
.size ffi_csky_trampoline, .-ffi_csky_trampoline
|
||||
|
||||
CSKY_FUNC_START ffi_csky_cacheflush
|
||||
lrw r1, 123
|
||||
trap 0
|
||||
rts
|
||||
|
||||
.size ffi_csky_cacheflush, .-ffi_csky_cacheflush
|
||||
|
||||
#endif /* __CSKYABIV2__ */
|
|
@ -438,6 +438,11 @@ DEFAULT_MMAP_THRESHOLD default: 256K
|
|||
|
||||
*/
|
||||
|
||||
#if defined __linux__ && !defined _GNU_SOURCE
|
||||
/* mremap() on Linux requires this via sys/mman.h */
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef _WIN32
|
||||
#define WIN32 1
|
||||
|
@ -2366,7 +2371,7 @@ static size_t traverse_and_check(mstate m);
|
|||
|
||||
#else /* GNUC */
|
||||
#if USE_BUILTIN_FFS
|
||||
#define compute_bit2idx(X, I) I = ffs(X)-1
|
||||
#define compute_bit2idx(X, I) I = __builtin_ffs(X)-1
|
||||
|
||||
#else /* USE_BUILTIN_FFS */
|
||||
#define compute_bit2idx(X, I)\
|
||||
|
|
|
@ -107,7 +107,7 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
|
|||
count += z;
|
||||
}
|
||||
|
||||
return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
|
||||
return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
|
@ -118,7 +118,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
else
|
||||
cif->flags = cif->rtype->size;
|
||||
|
||||
cif->bytes = ALIGN (cif->bytes, 8);
|
||||
cif->bytes = FFI_ALIGN (cif->bytes, 8);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
|
|
@ -220,8 +220,8 @@ hfa_element_type (ffi_type *type, int nested)
|
|||
|
||||
/* Perform machine dependent cif processing. */
|
||||
|
||||
ffi_status
|
||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
static ffi_status
|
||||
ffi_prep_cif_machdep_core(ffi_cif *cif)
|
||||
{
|
||||
int flags;
|
||||
|
||||
|
@ -271,6 +271,22 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
ffi_status
|
||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
cif->nfixedargs = cif->nargs;
|
||||
return ffi_prep_cif_machdep_core(cif);
|
||||
}
|
||||
|
||||
ffi_status
|
||||
ffi_prep_cif_machdep_var(ffi_cif *cif,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs MAYBE_UNUSED)
|
||||
{
|
||||
cif->nfixedargs = nfixedargs;
|
||||
return ffi_prep_cif_machdep_core(cif);
|
||||
}
|
||||
|
||||
extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
|
||||
|
||||
void
|
||||
|
@ -454,10 +470,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||
ffi_cif *cif;
|
||||
void **avalue;
|
||||
ffi_type **p_arg;
|
||||
long i, avn, gpcount, fpcount;
|
||||
long i, avn, gpcount, fpcount, nfixedargs;
|
||||
|
||||
cif = closure->cif;
|
||||
avn = cif->nargs;
|
||||
nfixedargs = cif->nfixedargs;
|
||||
avalue = alloca (avn * sizeof (void *));
|
||||
|
||||
/* If the structure return value is passed in memory get that location
|
||||
|
@ -468,6 +485,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||
gpcount = fpcount = 0;
|
||||
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
|
||||
{
|
||||
int named = i < nfixedargs;
|
||||
switch ((*p_arg)->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
|
@ -491,7 +509,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
if (gpcount < 8 && fpcount < 8)
|
||||
if (named && gpcount < 8 && fpcount < 8)
|
||||
{
|
||||
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||
float result;
|
||||
|
@ -505,7 +523,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
if (gpcount < 8 && fpcount < 8)
|
||||
if (named && gpcount < 8 && fpcount < 8)
|
||||
{
|
||||
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||
double result;
|
||||
|
@ -521,7 +539,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
|
|||
case FFI_TYPE_LONGDOUBLE:
|
||||
if (gpcount & 1)
|
||||
gpcount++;
|
||||
if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
|
||||
if (LDBL_MANT_DIG == 64 && named && gpcount < 8 && fpcount < 8)
|
||||
{
|
||||
fpreg *addr = &stack->fp_regs[fpcount++];
|
||||
__float80 result;
|
||||
|
|
|
@ -50,6 +50,7 @@ typedef enum ffi_abi {
|
|||
#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
|
||||
/* can be interpreted as a C function */
|
||||
/* descriptor: */
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC 1
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -175,7 +175,6 @@ ffi_call_unix:
|
|||
;;
|
||||
|
||||
.Lst_small_struct:
|
||||
add sp = -16, sp
|
||||
cmp.lt p6, p0 = 8, in3
|
||||
cmp.lt p7, p0 = 16, in3
|
||||
cmp.lt p8, p0 = 24, in3
|
||||
|
@ -191,6 +190,12 @@ ffi_call_unix:
|
|||
(p8) st8 [r18] = r11
|
||||
mov out1 = sp
|
||||
mov out2 = in3
|
||||
;;
|
||||
// ia64 software calling convention requires
|
||||
// top 16 bytes of stack to be scratch space
|
||||
// PLT resolver uses that scratch space at
|
||||
// 'memcpy' symbol reolution time
|
||||
add sp = -16, sp
|
||||
br.call.sptk.many b0 = memcpy#
|
||||
;;
|
||||
mov ar.pfs = loc0
|
||||
|
@ -529,6 +534,7 @@ ffi_closure_unix:
|
|||
data8 @pcrel(.Lst_int64) // FFI_TYPE_SINT64
|
||||
data8 @pcrel(.Lst_void) // FFI_TYPE_STRUCT
|
||||
data8 @pcrel(.Lst_int64) // FFI_TYPE_POINTER
|
||||
data8 @pcrel(.Lst_void) // FFI_TYPE_COMPLEX (not implemented)
|
||||
data8 @pcrel(.Lst_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT
|
||||
data8 @pcrel(.Lst_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT
|
||||
data8 @pcrel(.Lst_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE
|
||||
|
@ -550,6 +556,7 @@ ffi_closure_unix:
|
|||
data8 @pcrel(.Lld_int) // FFI_TYPE_SINT64
|
||||
data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT
|
||||
data8 @pcrel(.Lld_int) // FFI_TYPE_POINTER
|
||||
data8 @pcrel(.Lld_void) // FFI_TYPE_COMPLEX (not implemented)
|
||||
data8 @pcrel(.Lld_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT
|
||||
data8 @pcrel(.Lld_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT
|
||||
data8 @pcrel(.Lld_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE
|
||||
|
|
|
@ -114,7 +114,7 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args)
|
|||
default:
|
||||
*args = raw;
|
||||
raw +=
|
||||
ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
|
||||
FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args)
|
|||
#else /* FFI_SIZEOF_JAVA_RAW != 8 */
|
||||
*args = (void*) raw;
|
||||
raw +=
|
||||
ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
|
||||
FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
|
||||
#endif /* FFI_SIZEOF_JAVA_RAW == 8 */
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw)
|
|||
#else
|
||||
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
|
||||
raw +=
|
||||
ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
|
||||
FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
5
libffi/src/kvx/asm.h
Normal file
5
libffi/src/kvx/asm.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* args are passed on registers from r0 up to r11 => 12*8 bytes */
|
||||
#define REG_ARGS_SIZE (12*8)
|
||||
#define KVX_REGISTER_SIZE (8)
|
||||
#define KVX_ABI_SLOT_SIZE (KVX_REGISTER_SIZE)
|
||||
#define KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE (4*KVX_ABI_SLOT_SIZE)
|
273
libffi/src/kvx/ffi.c
Normal file
273
libffi/src/kvx/ffi.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
/* Copyright (c) 2020 Kalray
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
#if defined(__kvx__)
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include "ffi_common.h"
|
||||
#include "asm.h"
|
||||
|
||||
#define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1)
|
||||
#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
#define KVX_ABI_STACK_ALIGNMENT (32)
|
||||
#define KVX_ABI_STACK_ARG_ALIGNMENT (8)
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#ifdef FFI_DEBUG
|
||||
#define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while(0)
|
||||
#else
|
||||
#define DEBUG_PRINT(...)
|
||||
#endif
|
||||
|
||||
struct ret_value {
|
||||
unsigned long int r0;
|
||||
unsigned long int r1;
|
||||
unsigned long int r2;
|
||||
unsigned long int r3;
|
||||
};
|
||||
|
||||
extern struct ret_value ffi_call_SYSV(unsigned total_size,
|
||||
unsigned size,
|
||||
extended_cif *ecif,
|
||||
unsigned *rvalue_addr,
|
||||
void *fn,
|
||||
unsigned int_ext_method);
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
cif->flags = cif->rtype->size;
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
/* 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, unsigned int arg_slots_size, extended_cif *ecif)
|
||||
{
|
||||
char *stacktemp = stack;
|
||||
char *current_arg_passed_by_value = stack + arg_slots_size;
|
||||
int i, s;
|
||||
ffi_type **arg;
|
||||
int count = 0;
|
||||
ffi_cif *cif = ecif->cif;
|
||||
void **argv = ecif->avalue;
|
||||
|
||||
arg = cif->arg_types;
|
||||
|
||||
DEBUG_PRINT("stack: %p\n", stack);
|
||||
DEBUG_PRINT("arg_slots_size: %u\n", arg_slots_size);
|
||||
DEBUG_PRINT("current_arg_passed_by_value: %p\n", current_arg_passed_by_value);
|
||||
DEBUG_PRINT("ecif: %p\n", ecif);
|
||||
DEBUG_PRINT("ecif->avalue: %p\n", ecif->avalue);
|
||||
|
||||
for (i = 0; i < cif->nargs; i++) {
|
||||
|
||||
s = KVX_ABI_SLOT_SIZE;
|
||||
switch((*arg)->type) {
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
DEBUG_PRINT("INT64/32/16/8/FLOAT/DOUBLE or POINTER @%p\n", stack);
|
||||
*(uint64_t *) stack = *(uint64_t *)(* argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_COMPLEX:
|
||||
if ((*arg)->size == 8)
|
||||
*(_Complex float *) stack = *(_Complex float *)(* argv);
|
||||
else if ((*arg)->size == 16) {
|
||||
*(_Complex double *) stack = *(_Complex double *)(* argv);
|
||||
s = 16;
|
||||
} else
|
||||
abort();
|
||||
break;
|
||||
case FFI_TYPE_STRUCT: {
|
||||
char *value;
|
||||
unsigned int written_size = 0;
|
||||
DEBUG_PRINT("struct by value @%p\n", stack);
|
||||
if ((*arg)->size > KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE) {
|
||||
DEBUG_PRINT("big struct\n");
|
||||
*(uint64_t *) stack = (uintptr_t)current_arg_passed_by_value;
|
||||
value = current_arg_passed_by_value;
|
||||
current_arg_passed_by_value += (*arg)->size;
|
||||
written_size = KVX_ABI_SLOT_SIZE;
|
||||
} else {
|
||||
value = stack;
|
||||
written_size = (*arg)->size;
|
||||
}
|
||||
memcpy(value, *argv, (*arg)->size);
|
||||
s = ALIGN(written_size, KVX_ABI_STACK_ARG_ALIGNMENT);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Error: unsupported arg type %d\n", (*arg)->type);
|
||||
abort();
|
||||
break;
|
||||
|
||||
}
|
||||
stack += s;
|
||||
count += s;
|
||||
argv++;
|
||||
arg++;
|
||||
}
|
||||
#ifdef FFI_DEBUG
|
||||
FFI_ASSERT(((intptr_t)(stacktemp + REG_ARGS_SIZE) & (KVX_ABI_STACK_ALIGNMENT-1)) == 0);
|
||||
#endif
|
||||
return stacktemp + REG_ARGS_SIZE;
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing when we have a variadic function */
|
||||
|
||||
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
|
||||
unsigned int ntotalargs)
|
||||
{
|
||||
cif->flags = cif->rtype->size;
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
static unsigned long handle_small_int_ext(kvx_intext_method *int_ext_method,
|
||||
const ffi_type *rtype)
|
||||
{
|
||||
switch (rtype->type) {
|
||||
case FFI_TYPE_SINT8:
|
||||
*int_ext_method = KVX_RET_SXBD;
|
||||
return KVX_REGISTER_SIZE;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
*int_ext_method = KVX_RET_SXHD;
|
||||
return KVX_REGISTER_SIZE;
|
||||
|
||||
case FFI_TYPE_SINT32:
|
||||
*int_ext_method = KVX_RET_SXWD;
|
||||
return KVX_REGISTER_SIZE;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
*int_ext_method = KVX_RET_ZXBD;
|
||||
return KVX_REGISTER_SIZE;
|
||||
|
||||
case FFI_TYPE_UINT16:
|
||||
*int_ext_method = KVX_RET_ZXHD;
|
||||
return KVX_REGISTER_SIZE;
|
||||
|
||||
case FFI_TYPE_UINT32:
|
||||
*int_ext_method = KVX_RET_ZXWD;
|
||||
return KVX_REGISTER_SIZE;
|
||||
|
||||
default:
|
||||
*int_ext_method = KVX_RET_NONE;
|
||||
return rtype->size;
|
||||
}
|
||||
}
|
||||
|
||||
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
int i;
|
||||
unsigned long int slot_fitting_args_size = 0;
|
||||
unsigned long int total_size = 0;
|
||||
unsigned long int big_struct_size = 0;
|
||||
kvx_intext_method int_extension_method;
|
||||
ffi_type **arg;
|
||||
struct ret_value local_rvalue = {0};
|
||||
size_t wb_size;
|
||||
|
||||
|
||||
/* Calculate size to allocate on stack */
|
||||
for (i = 0, arg = cif->arg_types; i < cif->nargs; i++, arg++) {
|
||||
DEBUG_PRINT("argument %d, type %d, size %lu\n", i, (*arg)->type, (*arg)->size);
|
||||
if (((*arg)->type == FFI_TYPE_STRUCT) || ((*arg)->type == FFI_TYPE_COMPLEX)) {
|
||||
if ((*arg)->size <= KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE) {
|
||||
slot_fitting_args_size += ALIGN((*arg)->size, KVX_ABI_SLOT_SIZE);
|
||||
} else {
|
||||
slot_fitting_args_size += KVX_ABI_SLOT_SIZE; /* aggregate passed by reference */
|
||||
big_struct_size += ALIGN((*arg)->size, KVX_ABI_SLOT_SIZE);
|
||||
}
|
||||
} else if ((*arg)->size <= KVX_ABI_SLOT_SIZE) {
|
||||
slot_fitting_args_size += KVX_ABI_SLOT_SIZE;
|
||||
} else {
|
||||
printf("Error: unsupported arg size %ld arg type %d\n", (*arg)->size, (*arg)->type);
|
||||
abort(); /* should never happen? */
|
||||
}
|
||||
}
|
||||
|
||||
extended_cif ecif;
|
||||
ecif.cif = cif;
|
||||
ecif.avalue = avalue;
|
||||
ecif.rvalue = rvalue;
|
||||
|
||||
/* This implementation allocates anyway for all register based args */
|
||||
slot_fitting_args_size = max(slot_fitting_args_size, REG_ARGS_SIZE);
|
||||
total_size = slot_fitting_args_size + big_struct_size;
|
||||
total_size = ALIGN(total_size, KVX_ABI_STACK_ALIGNMENT);
|
||||
|
||||
/* wb_size: write back size, the size we will need to write back to user
|
||||
* provided buffer. In theory it should always be cif->flags which is
|
||||
* cif->rtype->size. But libffi API mandates that for integral types
|
||||
* of size <= system register size, then we *MUST* write back
|
||||
* the size of system register size.
|
||||
* in our case, if size <= 8 bytes we must write back 8 bytes.
|
||||
* floats, complex and structs are not affected, only integrals.
|
||||
*/
|
||||
wb_size = handle_small_int_ext(&int_extension_method, cif->rtype);
|
||||
|
||||
switch (cif->abi) {
|
||||
case FFI_SYSV:
|
||||
DEBUG_PRINT("total_size: %lu\n", total_size);
|
||||
DEBUG_PRINT("slot fitting args size: %lu\n", slot_fitting_args_size);
|
||||
DEBUG_PRINT("rvalue: %p\n", rvalue);
|
||||
DEBUG_PRINT("fn: %p\n", fn);
|
||||
DEBUG_PRINT("rsize: %u\n", cif->flags);
|
||||
DEBUG_PRINT("wb_size: %u\n", wb_size);
|
||||
DEBUG_PRINT("int_extension_method: %u\n", int_extension_method);
|
||||
local_rvalue = ffi_call_SYSV(total_size, slot_fitting_args_size,
|
||||
&ecif, rvalue, fn, int_extension_method);
|
||||
if ((cif->flags <= KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE)
|
||||
&& (cif->rtype->type != FFI_TYPE_VOID))
|
||||
memcpy(rvalue, &local_rvalue, wb_size);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Closures not supported yet */
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
return FFI_BAD_ABI;
|
||||
}
|
||||
|
||||
#endif /* (__kvx__) */
|
75
libffi/src/kvx/ffitarget.h
Normal file
75
libffi/src/kvx/ffitarget.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffitarget.h - Copyright (c) 2020 Kalray
|
||||
|
||||
KVX Target configuration macros
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef LIBFFI_TARGET_H
|
||||
#define LIBFFI_TARGET_H
|
||||
|
||||
#ifndef LIBFFI_H
|
||||
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
|
||||
#endif
|
||||
|
||||
/* ---- System specific configurations ----------------------------------- */
|
||||
|
||||
#ifndef LIBFFI_ASM
|
||||
typedef unsigned long ffi_arg;
|
||||
typedef signed long ffi_sarg;
|
||||
|
||||
typedef enum ffi_abi {
|
||||
FFI_FIRST_ABI = 0,
|
||||
FFI_SYSV,
|
||||
FFI_LAST_ABI,
|
||||
FFI_DEFAULT_ABI = FFI_SYSV
|
||||
} ffi_abi;
|
||||
|
||||
/* Those values are set depending on return type
|
||||
* they are used in the assembly code in sysv.S
|
||||
*/
|
||||
typedef enum kvx_intext_method {
|
||||
KVX_RET_NONE = 0,
|
||||
KVX_RET_SXBD = 1,
|
||||
KVX_RET_SXHD = 2,
|
||||
KVX_RET_SXWD = 3,
|
||||
KVX_RET_ZXBD = 4,
|
||||
KVX_RET_ZXHD = 5,
|
||||
KVX_RET_ZXWD = 6
|
||||
} kvx_intext_method;
|
||||
|
||||
#endif
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
/* This is only to allow Python to compile
|
||||
* but closures are not supported yet
|
||||
*/
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_TRAMPOLINE_SIZE 0
|
||||
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC 1
|
||||
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
||||
#endif
|
||||
|
127
libffi/src/kvx/sysv.S
Normal file
127
libffi/src/kvx/sysv.S
Normal file
|
@ -0,0 +1,127 @@
|
|||
/* Copyright (c) 2020 Kalray
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
#if defined(__kvx__)
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
#include <ffi_cfi.h>
|
||||
#include <kvx/asm.h>
|
||||
|
||||
.text
|
||||
.global ffi_call_SYSV
|
||||
.type ffi_call_SYSV, @function
|
||||
.type ffi_prep_args, @function
|
||||
.align 8
|
||||
|
||||
/* ffi_call_SYSV
|
||||
|
||||
r0: total size to allocate on stack
|
||||
r1: size of arg slots
|
||||
r2: extended cif structure, DO NOT REMOVE: it is used by ffi_prep_args()
|
||||
r3: return value address
|
||||
r4: function to call
|
||||
r5: integer sign extension method to be used
|
||||
*/
|
||||
ffi_call_SYSV:
|
||||
addd $r12 = $r12, -64
|
||||
so (-32)[$r12] = $r20r21r22r23
|
||||
;;
|
||||
sd (0)[$r12] = $r24
|
||||
;;
|
||||
get $r23 = $ra
|
||||
copyd $r20 = $r12
|
||||
sbfd $r12 = $r0, $r12
|
||||
;;
|
||||
copyd $r0 = $r12
|
||||
copyd $r21 = $r3
|
||||
copyd $r22 = $r4
|
||||
copyd $r24 = $r5
|
||||
call ffi_prep_args
|
||||
;;
|
||||
lo $r8r9r10r11 = (64)[$r12]
|
||||
;;
|
||||
lo $r4r5r6r7 = (32)[$r12]
|
||||
;;
|
||||
lo $r0r1r2r3 = (0)[$r12]
|
||||
copyd $r12 = $r0
|
||||
/* $r15 is the register used by the ABI to return big (>32 bytes)
|
||||
* structs by value.
|
||||
* It is also referred to as the "struct register" in the ABI.
|
||||
*/
|
||||
copyd $r15 = $r21
|
||||
icall $r22
|
||||
;;
|
||||
pcrel $r4 = @pcrel(.Ltable)
|
||||
cb.deqz $r24 ? .Lend
|
||||
;;
|
||||
addx8d $r24 = $r24, $r4
|
||||
;;
|
||||
igoto $r24
|
||||
;;
|
||||
.Ltable:
|
||||
0: /* we should never arrive here */
|
||||
goto .Lerror
|
||||
nop
|
||||
;;
|
||||
1: /* Sign extend byte to double */
|
||||
sxbd $r0 = $r0
|
||||
goto .Lend
|
||||
;;
|
||||
2: /* Sign extend half to double */
|
||||
sxhd $r0 = $r0
|
||||
goto .Lend
|
||||
;;
|
||||
3: /* Sign extend word to double */
|
||||
sxwd $r0 = $r0
|
||||
goto .Lend
|
||||
;;
|
||||
4: /* Zero extend byte to double */
|
||||
zxbd $r0 = $r0
|
||||
goto .Lend
|
||||
;;
|
||||
5: /* Zero extend half to double */
|
||||
zxhd $r0 = $r0
|
||||
goto .Lend
|
||||
;;
|
||||
6: /* Zero extend word to double */
|
||||
zxwd $r0 = $r0
|
||||
/* Fallthrough to .Lend */
|
||||
;;
|
||||
.Lend:
|
||||
ld $r24 = (0)[$r12]
|
||||
;;
|
||||
set $ra = $r23
|
||||
lo $r20r21r22r23 = (32)[$r20]
|
||||
addd $r12 = $r20, 64
|
||||
;;
|
||||
ret
|
||||
;;
|
||||
.Lerror:
|
||||
errop
|
||||
;;
|
||||
|
||||
#endif /* __kvx__ */
|
||||
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
|
@ -61,7 +61,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
|
|||
|
||||
/* Align if necessary. */
|
||||
if (((*p_arg)->alignment - 1) & (unsigned) argp)
|
||||
argp = (char *) ALIGN (argp, (*p_arg)->alignment);
|
||||
argp = (char *) FFI_ALIGN (argp, (*p_arg)->alignment);
|
||||
|
||||
if (avn != 0)
|
||||
{
|
||||
|
|
|
@ -105,7 +105,7 @@ ffi_prep_args (void *stack, extended_cif *ecif)
|
|||
|
||||
/* Align if necessary. */
|
||||
if ((sizeof(int) - 1) & z)
|
||||
z = ALIGN(z, sizeof(int));
|
||||
z = FFI_ALIGN(z, sizeof(int));
|
||||
}
|
||||
|
||||
p_argv++;
|
||||
|
@ -297,7 +297,7 @@ ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
|
|||
|
||||
/* Align if necessary */
|
||||
if ((sizeof(int) - 1) & z)
|
||||
z = ALIGN(z, sizeof(int));
|
||||
z = FFI_ALIGN(z, sizeof(int));
|
||||
}
|
||||
|
||||
p_argv++;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
sysv.S - Copyright (c) 2012 Alan Hourihane
|
||||
Copyright (c) 1998, 2012 Andreas Schwab
|
||||
Copyright (c) 2008 Red Hat, Inc.
|
||||
Copyright (c) 2012 Thorsten Glaser
|
||||
Copyright (c) 2012, 2016 Thorsten Glaser
|
||||
|
||||
m68k Foreign Function Interface
|
||||
|
||||
|
@ -72,6 +72,15 @@ CALLFUNC(ffi_call_SYSV):
|
|||
pea 4(%sp)
|
||||
#if !defined __PIC__
|
||||
jsr CALLFUNC(ffi_prep_args)
|
||||
#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
|
||||
move.l _current_shared_library_a5_offset_(%a5),%a0
|
||||
move.l CALLFUNC(ffi_prep_args@GOT)(%a0),%a0
|
||||
jsr (%a0)
|
||||
#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
|
||||
move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
|
||||
lea (-6,%pc,%a0),%a0
|
||||
move.l CALLFUNC(ffi_prep_args@GOT)(%a0),%a0
|
||||
jsr (%a0)
|
||||
#else
|
||||
bsr.l CALLFUNC(ffi_prep_args@PLTPC)
|
||||
#endif
|
||||
|
@ -215,6 +224,15 @@ CALLFUNC(ffi_closure_SYSV):
|
|||
move.l %a0,-(%sp)
|
||||
#if !defined __PIC__
|
||||
jsr CALLFUNC(ffi_closure_SYSV_inner)
|
||||
#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
|
||||
move.l _current_shared_library_a5_offset_(%a5),%a0
|
||||
move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
|
||||
jsr (%a0)
|
||||
#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
|
||||
move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
|
||||
lea (-6,%pc,%a0),%a0
|
||||
move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
|
||||
jsr (%a0)
|
||||
#else
|
||||
bsr.l CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
|
||||
#endif
|
||||
|
@ -317,6 +335,15 @@ CALLFUNC(ffi_closure_struct_SYSV):
|
|||
move.l %a0,-(%sp)
|
||||
#if !defined __PIC__
|
||||
jsr CALLFUNC(ffi_closure_SYSV_inner)
|
||||
#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
|
||||
move.l _current_shared_library_a5_offset_(%a5),%a0
|
||||
move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
|
||||
jsr (%a0)
|
||||
#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
|
||||
move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
|
||||
lea (-6,%pc,%a0),%a0
|
||||
move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
|
||||
jsr (%a0)
|
||||
#else
|
||||
bsr.l CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
|
||||
#endif
|
||||
|
|
|
@ -134,7 +134,7 @@ ffi_prep_args (void *stack, extended_cif *ecif)
|
|||
/* Enforce proper stack alignment of 64-bit types */
|
||||
if (argp == stackp && a > sizeof (int))
|
||||
{
|
||||
stackp = (char *) ALIGN(stackp, a);
|
||||
stackp = (char *) FFI_ALIGN(stackp, a);
|
||||
argp = stackp;
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ ffi_prep_args (void *stack, extended_cif *ecif)
|
|||
|
||||
/* Align if necessary. */
|
||||
if ((sizeof (int) - 1) & z)
|
||||
z = ALIGN(z, sizeof (int));
|
||||
z = FFI_ALIGN(z, sizeof (int));
|
||||
|
||||
p_argv++;
|
||||
|
||||
|
@ -320,7 +320,7 @@ ffi_prep_closure_args_OBSD (ffi_cif *cif, void **avalue, unsigned int *regp,
|
|||
/* Enforce proper stack alignment of 64-bit types */
|
||||
if (argp == stackp && a > sizeof (int))
|
||||
{
|
||||
stackp = (char *) ALIGN(stackp, a);
|
||||
stackp = (char *) FFI_ALIGN(stackp, a);
|
||||
argp = stackp;
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ ffi_prep_closure_args_OBSD (ffi_cif *cif, void **avalue, unsigned int *regp,
|
|||
|
||||
/* Align if necessary */
|
||||
if ((sizeof (int) - 1) & z)
|
||||
z = ALIGN(z, sizeof (int));
|
||||
z = FFI_ALIGN(z, sizeof (int));
|
||||
|
||||
p_argv++;
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
|
|||
argp -= z;
|
||||
|
||||
/* Align if necessary */
|
||||
argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
|
||||
argp = (char *) FFI_ALIGN_DOWN(FFI_ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
|
||||
|
||||
if (z < sizeof(int)) {
|
||||
z = sizeof(int);
|
||||
|
@ -93,7 +93,7 @@ unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
|
|||
|
||||
/* return the size of the arguments to be passed in registers,
|
||||
padded to an 8 byte boundary to preserve stack alignment */
|
||||
return ALIGN(MIN(stack - argp, 6*4), 8);
|
||||
return FFI_ALIGN(MIN(stack - argp, 6*4), 8);
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
|
@ -112,20 +112,20 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
|
||||
/* Add any padding if necessary */
|
||||
if (((*ptr)->alignment - 1) & bytes)
|
||||
bytes = ALIGN(bytes, (*ptr)->alignment);
|
||||
bytes = FFI_ALIGN(bytes, (*ptr)->alignment);
|
||||
|
||||
bytes += ALIGN((*ptr)->size, 4);
|
||||
bytes += FFI_ALIGN((*ptr)->size, 4);
|
||||
}
|
||||
|
||||
/* Ensure arg space is aligned to an 8-byte boundary */
|
||||
bytes = ALIGN(bytes, 8);
|
||||
bytes = FFI_ALIGN(bytes, 8);
|
||||
|
||||
/* Make space for the return structure pointer */
|
||||
if (cif->rtype->type == FFI_TYPE_STRUCT) {
|
||||
bytes += sizeof(void*);
|
||||
|
||||
/* Ensure stack is aligned to an 8-byte boundary */
|
||||
bytes = ALIGN(bytes, 8);
|
||||
bytes = FFI_ALIGN(bytes, 8);
|
||||
}
|
||||
|
||||
cif->bytes = bytes;
|
||||
|
@ -319,7 +319,7 @@ static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
|||
if (alignment < 4)
|
||||
alignment = 4;
|
||||
if ((alignment - 1) & (unsigned)argp)
|
||||
argp = (char *) ALIGN(argp, alignment);
|
||||
argp = (char *) FFI_ALIGN(argp, alignment);
|
||||
|
||||
z = (*p_arg)->size;
|
||||
*p_argv = (void*) argp;
|
||||
|
|
|
@ -35,7 +35,7 @@ extern void ffi_closure_SYSV(void);
|
|||
|
||||
#define WORD_SIZE sizeof(unsigned int)
|
||||
#define ARGS_REGISTER_SIZE (WORD_SIZE * 6)
|
||||
#define WORD_ALIGN(x) ALIGN(x, WORD_SIZE)
|
||||
#define WORD_FFI_ALIGN(x) FFI_ALIGN(x, WORD_SIZE)
|
||||
|
||||
/* ffi_prep_args is called by the assembly routine once stack space
|
||||
has been allocated for the function's arguments */
|
||||
|
@ -46,12 +46,12 @@ void ffi_prep_args(void* stack, extended_cif* ecif)
|
|||
void** p_argv;
|
||||
void* stack_args_p = stack;
|
||||
|
||||
p_argv = ecif->avalue;
|
||||
|
||||
if (ecif == NULL || ecif->cif == NULL) {
|
||||
return; /* no description to prepare */
|
||||
}
|
||||
|
||||
p_argv = ecif->avalue;
|
||||
|
||||
if ((ecif->cif->rtype != NULL) &&
|
||||
(ecif->cif->rtype->type == FFI_TYPE_STRUCT))
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ void ffi_prep_args(void* stack, extended_cif* ecif)
|
|||
int type = (*p_arg)->type;
|
||||
void* value = p_argv[i];
|
||||
char* addr = stack_args_p;
|
||||
int aligned_size = WORD_ALIGN(size);
|
||||
int aligned_size = WORD_FFI_ALIGN(size);
|
||||
|
||||
/* force word alignment on the stack */
|
||||
stack_args_p += aligned_size;
|
||||
|
@ -259,7 +259,7 @@ void ffi_closure_call_SYSV(void* register_args, void* stack_args,
|
|||
avalue[i] = ptr;
|
||||
break;
|
||||
}
|
||||
ptr += WORD_ALIGN(arg_types[i]->size);
|
||||
ptr += WORD_FFI_ALIGN(arg_types[i]->size);
|
||||
}
|
||||
|
||||
/* set the return type info passed back to the wrapper */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
@ -38,7 +39,9 @@
|
|||
#endif
|
||||
|
||||
#ifndef USE__BUILTIN___CLEAR_CACHE
|
||||
# if defined(__OpenBSD__)
|
||||
# if defined(__FreeBSD__)
|
||||
# include <machine/sysarch.h>
|
||||
# elif defined(__OpenBSD__)
|
||||
# include <mips64/sysarch.h>
|
||||
# else
|
||||
# include <sys/cachectl.h>
|
||||
|
@ -116,7 +119,7 @@ static void ffi_prep_args(char *stack,
|
|||
|
||||
if ((a - 1) & (unsigned long) argp)
|
||||
{
|
||||
argp = (char *) ALIGN(argp, a);
|
||||
argp = (char *) FFI_ALIGN(argp, a);
|
||||
FIX_ARGP;
|
||||
}
|
||||
|
||||
|
@ -247,7 +250,7 @@ calc_n32_struct_flags(int soft_float, ffi_type *arg,
|
|||
while ((e = arg->elements[index]))
|
||||
{
|
||||
/* Align this object. */
|
||||
*loc = ALIGN(*loc, e->alignment);
|
||||
*loc = FFI_ALIGN(*loc, e->alignment);
|
||||
if (e->type == FFI_TYPE_DOUBLE)
|
||||
{
|
||||
/* Already aligned to FFI_SIZEOF_ARG. */
|
||||
|
@ -262,7 +265,7 @@ calc_n32_struct_flags(int soft_float, ffi_type *arg,
|
|||
index++;
|
||||
}
|
||||
/* Next Argument register at alignment of FFI_SIZEOF_ARG. */
|
||||
*arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
*arg_reg = FFI_ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
@ -322,9 +325,10 @@ calc_n32_return_struct_flags(int soft_float, ffi_type *arg)
|
|||
#endif
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
|
||||
{
|
||||
cif->flags = 0;
|
||||
cif->mips_nfixedargs = nfixedargs;
|
||||
|
||||
#ifdef FFI_MIPS_O32
|
||||
/* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT
|
||||
|
@ -333,7 +337,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
|
||||
if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32)
|
||||
{
|
||||
if (cif->nargs > 0)
|
||||
if (cif->nargs > 0 && cif->nargs == nfixedargs)
|
||||
{
|
||||
switch ((cif->arg_types)[0]->type)
|
||||
{
|
||||
|
@ -450,7 +454,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
while (count-- > 0 && arg_reg < 8)
|
||||
{
|
||||
type = (cif->arg_types)[index]->type;
|
||||
if (soft_float)
|
||||
|
||||
// Pass variadic arguments in integer registers even if they're floats
|
||||
if (soft_float || index >= nfixedargs)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -474,9 +480,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
break;
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
/* Align it. */
|
||||
arg_reg = ALIGN(arg_reg, 2);
|
||||
arg_reg = FFI_ALIGN(arg_reg, 2);
|
||||
/* Treat it as two adjacent doubles. */
|
||||
if (soft_float)
|
||||
if (soft_float || index >= nfixedargs)
|
||||
{
|
||||
arg_reg += 2;
|
||||
}
|
||||
|
@ -493,7 +499,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
|
||||
case FFI_TYPE_STRUCT:
|
||||
loc = arg_reg * FFI_SIZEOF_ARG;
|
||||
cif->flags += calc_n32_struct_flags(soft_float,
|
||||
cif->flags += calc_n32_struct_flags(soft_float || index >= nfixedargs,
|
||||
(cif->arg_types)[index],
|
||||
&loc, &arg_reg);
|
||||
break;
|
||||
|
@ -578,17 +584,30 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
return ffi_prep_cif_machdep_int(cif, cif->nargs);
|
||||
}
|
||||
|
||||
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
|
||||
unsigned nfixedargs,
|
||||
unsigned ntotalargs MAYBE_UNUSED)
|
||||
{
|
||||
return ffi_prep_cif_machdep_int(cif, nfixedargs);
|
||||
}
|
||||
|
||||
/* Low level routine for calling O32 functions */
|
||||
extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
|
||||
extended_cif *, unsigned,
|
||||
unsigned, unsigned *, void (*)(void));
|
||||
unsigned, unsigned *, void (*)(void), void *closure);
|
||||
|
||||
/* Low level routine for calling N32 functions */
|
||||
extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
|
||||
extended_cif *, unsigned,
|
||||
unsigned, void *, void (*)(void));
|
||||
unsigned, void *, void (*)(void), void *closure);
|
||||
|
||||
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
void ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
extended_cif ecif;
|
||||
|
||||
|
@ -610,7 +629,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
|||
case FFI_O32:
|
||||
case FFI_O32_SOFT_FLOAT:
|
||||
ffi_call_O32(ffi_prep_args, &ecif, cif->bytes,
|
||||
cif->flags, ecif.rvalue, fn);
|
||||
cif->flags, ecif.rvalue, fn, closure);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
@ -642,7 +661,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
|||
#endif
|
||||
}
|
||||
ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
|
||||
cif->flags, rvalue_copy, fn);
|
||||
cif->flags, rvalue_copy, fn, closure);
|
||||
if (copy_rvalue)
|
||||
memcpy(ecif.rvalue, rvalue_copy + copy_offset, cif->rtype->size);
|
||||
}
|
||||
|
@ -655,11 +674,27 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, closure);
|
||||
}
|
||||
|
||||
|
||||
#if FFI_CLOSURES
|
||||
#if defined(FFI_MIPS_O32)
|
||||
extern void ffi_closure_O32(void);
|
||||
extern void ffi_go_closure_O32(void);
|
||||
#else
|
||||
extern void ffi_closure_N32(void);
|
||||
extern void ffi_go_closure_N32(void);
|
||||
#endif /* FFI_MIPS_O32 */
|
||||
|
||||
ffi_status
|
||||
|
@ -744,11 +779,13 @@ ffi_prep_closure_loc (ffi_closure *closure,
|
|||
closure->fun = fun;
|
||||
closure->user_data = user_data;
|
||||
|
||||
#if !defined(__FreeBSD__)
|
||||
#ifdef USE__BUILTIN___CLEAR_CACHE
|
||||
__builtin___clear_cache(clear_location, clear_location + FFI_TRAMPOLINE_SIZE);
|
||||
#else
|
||||
cacheflush (clear_location, FFI_TRAMPOLINE_SIZE, ICACHE);
|
||||
#endif
|
||||
#endif /* ! __FreeBSD__ */
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
|
@ -770,27 +807,28 @@ ffi_prep_closure_loc (ffi_closure *closure,
|
|||
* Based on the similar routine for sparc.
|
||||
*/
|
||||
int
|
||||
ffi_closure_mips_inner_O32 (ffi_closure *closure,
|
||||
ffi_closure_mips_inner_O32 (ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *rvalue, ffi_arg *ar,
|
||||
double *fpr)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
void **avaluep;
|
||||
ffi_arg *avalue;
|
||||
ffi_type **arg_types;
|
||||
int i, avn, argn, seen_int;
|
||||
|
||||
cif = closure->cif;
|
||||
avalue = alloca (cif->nargs * sizeof (ffi_arg));
|
||||
avaluep = alloca (cif->nargs * sizeof (ffi_arg));
|
||||
|
||||
seen_int = (cif->abi == FFI_O32_SOFT_FLOAT);
|
||||
seen_int = (cif->abi == FFI_O32_SOFT_FLOAT) || (cif->mips_nfixedargs != cif->nargs);
|
||||
argn = 0;
|
||||
|
||||
if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
|
||||
{
|
||||
rvalue = (void *)(UINT32)ar[0];
|
||||
rvalue = (void *)(uintptr_t)ar[0];
|
||||
argn = 1;
|
||||
seen_int = 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
@ -799,6 +837,8 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
|
|||
|
||||
while (i < avn)
|
||||
{
|
||||
if (arg_types[i]->alignment == 8 && (argn & 0x1))
|
||||
argn++;
|
||||
if (i < 2 && !seen_int &&
|
||||
(arg_types[i]->type == FFI_TYPE_FLOAT ||
|
||||
arg_types[i]->type == FFI_TYPE_DOUBLE ||
|
||||
|
@ -813,8 +853,6 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
|
|||
}
|
||||
else
|
||||
{
|
||||
if (arg_types[i]->alignment == 8 && (argn & 0x1))
|
||||
argn++;
|
||||
switch (arg_types[i]->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
|
@ -843,12 +881,12 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
|
|||
}
|
||||
seen_int = 1;
|
||||
}
|
||||
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
argn += FFI_ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
(closure->fun) (cif, rvalue, avaluep, closure->user_data);
|
||||
fun(cif, rvalue, avaluep, user_data);
|
||||
|
||||
if (cif->abi == FFI_O32_SOFT_FLOAT)
|
||||
{
|
||||
|
@ -884,7 +922,7 @@ copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
|
|||
char *argp;
|
||||
char *fpp;
|
||||
|
||||
o = ALIGN(offset, elt_type->alignment);
|
||||
o = FFI_ALIGN(offset, elt_type->alignment);
|
||||
arg_offset += o - offset;
|
||||
offset = o;
|
||||
argn += arg_offset / sizeof(ffi_arg);
|
||||
|
@ -924,11 +962,12 @@ copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
|
|||
*
|
||||
*/
|
||||
int
|
||||
ffi_closure_mips_inner_N32 (ffi_closure *closure,
|
||||
ffi_closure_mips_inner_N32 (ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *rvalue, ffi_arg *ar,
|
||||
ffi_arg *fpr)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
void **avaluep;
|
||||
ffi_arg *avalue;
|
||||
ffi_type **arg_types;
|
||||
|
@ -936,7 +975,6 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
|
|||
int soft_float;
|
||||
ffi_arg *argp;
|
||||
|
||||
cif = closure->cif;
|
||||
soft_float = cif->abi == FFI_N64_SOFT_FLOAT
|
||||
|| cif->abi == FFI_N32_SOFT_FLOAT;
|
||||
avalue = alloca (cif->nargs * sizeof (ffi_arg));
|
||||
|
@ -964,10 +1002,10 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
|
|||
|| arg_types[i]->type == FFI_TYPE_DOUBLE
|
||||
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE)
|
||||
{
|
||||
argp = (argn >= 8 || soft_float) ? ar + argn : fpr + argn;
|
||||
if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((unsigned)argp & (arg_types[i]->alignment-1)))
|
||||
argp = (argn >= 8 || i >= cif->mips_nfixedargs || soft_float) ? ar + argn : fpr + argn;
|
||||
if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((uintptr_t)argp & (arg_types[i]->alignment-1)))
|
||||
{
|
||||
argp=(ffi_arg*)ALIGN(argp,arg_types[i]->alignment);
|
||||
argp=(ffi_arg*)FFI_ALIGN(argp,arg_types[i]->alignment);
|
||||
argn++;
|
||||
}
|
||||
#if defined(__MIPSEB__) || defined(_MIPSEB)
|
||||
|
@ -982,7 +1020,7 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
|
|||
unsigned type = arg_types[i]->type;
|
||||
|
||||
if (arg_types[i]->alignment > sizeof(ffi_arg))
|
||||
argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
|
||||
argn = FFI_ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
|
||||
|
||||
argp = ar + argn;
|
||||
|
||||
|
@ -1033,7 +1071,7 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
|
|||
it was passed in registers. */
|
||||
avaluep[i] = alloca(arg_types[i]->size);
|
||||
copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
|
||||
argn, 0, ar, fpr, soft_float);
|
||||
argn, 0, ar, fpr, i >= cif->mips_nfixedargs || soft_float);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1043,16 +1081,54 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
|
|||
break;
|
||||
}
|
||||
}
|
||||
argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
|
||||
argn += FFI_ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
(closure->fun) (cif, rvalue, avaluep, closure->user_data);
|
||||
fun (cif, rvalue, avaluep, user_data);
|
||||
|
||||
return cif->flags >> (FFI_FLAG_BITS * 8);
|
||||
}
|
||||
|
||||
#endif /* FFI_MIPS_N32 */
|
||||
|
||||
#if defined(FFI_MIPS_O32)
|
||||
extern void ffi_closure_O32(void);
|
||||
extern void ffi_go_closure_O32(void);
|
||||
#else
|
||||
extern void ffi_closure_N32(void);
|
||||
extern void ffi_go_closure_N32(void);
|
||||
#endif /* FFI_MIPS_O32 */
|
||||
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*))
|
||||
{
|
||||
void * fn;
|
||||
|
||||
#if defined(FFI_MIPS_O32)
|
||||
if (cif->abi != FFI_O32 && cif->abi != FFI_O32_SOFT_FLOAT)
|
||||
return FFI_BAD_ABI;
|
||||
fn = ffi_go_closure_O32;
|
||||
#else
|
||||
#if _MIPS_SIM ==_ABIN32
|
||||
if (cif->abi != FFI_N32
|
||||
&& cif->abi != FFI_N32_SOFT_FLOAT)
|
||||
return FFI_BAD_ABI;
|
||||
#else
|
||||
if (cif->abi != FFI_N64
|
||||
&& cif->abi != FFI_N64_SOFT_FLOAT)
|
||||
return FFI_BAD_ABI;
|
||||
#endif
|
||||
fn = ffi_go_closure_N32;
|
||||
#endif /* FFI_MIPS_O32 */
|
||||
|
||||
closure->tramp = (void *)fn;
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
#endif /* FFI_CLOSURES */
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
|
||||
#endif
|
||||
|
||||
#ifdef linux
|
||||
#ifdef __linux__
|
||||
# include <asm/sgidefs.h>
|
||||
#elif defined(__rtems__)
|
||||
/*
|
||||
|
@ -41,7 +41,7 @@
|
|||
#define _MIPS_SIM_ABI32 1
|
||||
#define _MIPS_SIM_NABI32 2
|
||||
#define _MIPS_SIM_ABI64 3
|
||||
#elif !defined(__OpenBSD__)
|
||||
#elif !defined(__OpenBSD__) && !defined(__FreeBSD__)
|
||||
# include <sgidefs.h>
|
||||
#endif
|
||||
|
||||
|
@ -224,24 +224,21 @@ typedef enum ffi_abi {
|
|||
#endif
|
||||
} ffi_abi;
|
||||
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag; unsigned mips_nfixedargs
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC
|
||||
#endif /* !LIBFFI_ASM */
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#if defined(FFI_MIPS_O32)
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_TRAMPOLINE_SIZE 20
|
||||
#else
|
||||
/* N32/N64. */
|
||||
# define FFI_CLOSURES 1
|
||||
#if _MIPS_SIM==_ABI64
|
||||
#define FFI_TRAMPOLINE_SIZE 52
|
||||
#else
|
||||
#define FFI_TRAMPOLINE_SIZE 20
|
||||
#endif
|
||||
#endif /* FFI_MIPS_O32 */
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32)
|
||||
# define FFI_TRAMPOLINE_SIZE 20
|
||||
#else
|
||||
# define FFI_TRAMPOLINE_SIZE 56
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,8 +37,12 @@
|
|||
#define flags a3
|
||||
#define raddr a4
|
||||
#define fn a5
|
||||
#define closure a6
|
||||
|
||||
#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
|
||||
/* Note: to keep stack 16 byte aligned we need even number slots
|
||||
used 9 slots here
|
||||
*/
|
||||
#define SIZEOF_FRAME ( 10 * FFI_SIZEOF_ARG )
|
||||
|
||||
#ifdef __GNUC__
|
||||
.abicalls
|
||||
|
@ -51,24 +55,25 @@
|
|||
.globl ffi_call_N32
|
||||
.ent ffi_call_N32
|
||||
ffi_call_N32:
|
||||
.LFB3:
|
||||
.LFB0:
|
||||
.frame $fp, SIZEOF_FRAME, ra
|
||||
.mask 0xc0000000,-FFI_SIZEOF_ARG
|
||||
.fmask 0x00000000,0
|
||||
|
||||
# Prologue
|
||||
SUBU $sp, SIZEOF_FRAME # Frame size
|
||||
.LCFI0:
|
||||
.LCFI00:
|
||||
REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
|
||||
REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
|
||||
.LCFI1:
|
||||
.LCFI01:
|
||||
move $fp, $sp
|
||||
.LCFI3:
|
||||
.LCFI02:
|
||||
move t9, callback # callback function pointer
|
||||
REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
|
||||
REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
|
||||
REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
|
||||
REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
|
||||
REG_S closure, 6*FFI_SIZEOF_ARG($fp) # closure
|
||||
|
||||
# Allocate at least 4 words in the argstack
|
||||
move v0, bytes
|
||||
|
@ -109,6 +114,16 @@ loadregs:
|
|||
|
||||
REG_L t6, 3*FFI_SIZEOF_ARG($fp) # load the flags word into t6.
|
||||
|
||||
#ifdef __mips_soft_float
|
||||
REG_L a0, 0*FFI_SIZEOF_ARG(t9)
|
||||
REG_L a1, 1*FFI_SIZEOF_ARG(t9)
|
||||
REG_L a2, 2*FFI_SIZEOF_ARG(t9)
|
||||
REG_L a3, 3*FFI_SIZEOF_ARG(t9)
|
||||
REG_L a4, 4*FFI_SIZEOF_ARG(t9)
|
||||
REG_L a5, 5*FFI_SIZEOF_ARG(t9)
|
||||
REG_L a6, 6*FFI_SIZEOF_ARG(t9)
|
||||
REG_L a7, 7*FFI_SIZEOF_ARG(t9)
|
||||
#else
|
||||
and t4, t6, ((1<<FFI_FLAG_BITS)-1)
|
||||
REG_L a0, 0*FFI_SIZEOF_ARG(t9)
|
||||
beqz t4, arg1_next
|
||||
|
@ -195,11 +210,15 @@ arg7_next:
|
|||
arg8_doublep:
|
||||
l.d $f19, 7*FFI_SIZEOF_ARG(t9)
|
||||
arg8_next:
|
||||
#endif
|
||||
|
||||
callit:
|
||||
# Load the function pointer
|
||||
REG_L t9, 5*FFI_SIZEOF_ARG($fp)
|
||||
|
||||
# install the static chain(t7=$15)
|
||||
REG_L t7, 6*FFI_SIZEOF_ARG($fp)
|
||||
|
||||
# If the return value pointer is NULL, assume no return value.
|
||||
REG_L t5, 4*FFI_SIZEOF_ARG($fp)
|
||||
beqz t5, noretval
|
||||
|
@ -216,6 +235,7 @@ retint:
|
|||
b epilogue
|
||||
|
||||
retfloat:
|
||||
#ifndef __mips_soft_float
|
||||
bne t6, FFI_TYPE_FLOAT, retdouble
|
||||
jal t9
|
||||
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
|
||||
|
@ -274,6 +294,7 @@ retstruct_f_d:
|
|||
s.s $f0, 0(t4)
|
||||
s.d $f2, 8(t4)
|
||||
b epilogue
|
||||
#endif
|
||||
|
||||
retstruct_d_soft:
|
||||
bne t6, FFI_TYPE_STRUCT_D_SOFT, retstruct_f_soft
|
||||
|
@ -348,7 +369,7 @@ epilogue:
|
|||
ADDU $sp, SIZEOF_FRAME # Fix stack pointer
|
||||
j ra
|
||||
|
||||
.LFE3:
|
||||
.LFE0:
|
||||
.end ffi_call_N32
|
||||
|
||||
/* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
|
||||
|
@ -407,6 +428,41 @@ epilogue:
|
|||
#define RA_OFF2 (1 * FFI_SIZEOF_ARG)
|
||||
#define GP_OFF2 (0 * FFI_SIZEOF_ARG)
|
||||
|
||||
.align 2
|
||||
.globl ffi_go_closure_N32
|
||||
.ent ffi_go_closure_N32
|
||||
ffi_go_closure_N32:
|
||||
.LFB1:
|
||||
.frame $sp, SIZEOF_FRAME2, ra
|
||||
.mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
|
||||
.fmask 0x00000000,0
|
||||
SUBU $sp, SIZEOF_FRAME2
|
||||
.LCFI10:
|
||||
.cpsetup t9, GP_OFF2, ffi_go_closure_N32
|
||||
REG_S ra, RA_OFF2($sp) # Save return address
|
||||
.LCFI11:
|
||||
|
||||
REG_S a0, A0_OFF2($sp)
|
||||
REG_S a1, A1_OFF2($sp)
|
||||
REG_S a2, A2_OFF2($sp)
|
||||
REG_S a3, A3_OFF2($sp)
|
||||
REG_S a4, A4_OFF2($sp)
|
||||
REG_S a5, A5_OFF2($sp)
|
||||
|
||||
# Call ffi_closure_mips_inner_N32 to do the real work.
|
||||
LA t9, ffi_closure_mips_inner_N32
|
||||
REG_L a0, 8($15) # cif
|
||||
REG_L a1, 16($15) # fun
|
||||
move a2, t7 # userdata=closure
|
||||
ADDU a3, $sp, V0_OFF2 # rvalue
|
||||
ADDU a4, $sp, A0_OFF2 # ar
|
||||
ADDU a5, $sp, F12_OFF2 # fpr
|
||||
|
||||
b $do_closure
|
||||
|
||||
.LFE1:
|
||||
.end ffi_go_closure_N32
|
||||
|
||||
.align 2
|
||||
.globl ffi_closure_N32
|
||||
.ent ffi_closure_N32
|
||||
|
@ -416,21 +472,33 @@ ffi_closure_N32:
|
|||
.mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
|
||||
.fmask 0x00000000,0
|
||||
SUBU $sp, SIZEOF_FRAME2
|
||||
.LCFI5:
|
||||
.LCFI20:
|
||||
.cpsetup t9, GP_OFF2, ffi_closure_N32
|
||||
REG_S ra, RA_OFF2($sp) # Save return address
|
||||
.LCFI6:
|
||||
# Store all possible argument registers. If there are more than
|
||||
# fit in registers, then they were stored on the stack.
|
||||
.LCFI21:
|
||||
REG_S a0, A0_OFF2($sp)
|
||||
REG_S a1, A1_OFF2($sp)
|
||||
REG_S a2, A2_OFF2($sp)
|
||||
REG_S a3, A3_OFF2($sp)
|
||||
REG_S a4, A4_OFF2($sp)
|
||||
REG_S a5, A5_OFF2($sp)
|
||||
|
||||
# Call ffi_closure_mips_inner_N32 to do the real work.
|
||||
LA t9, ffi_closure_mips_inner_N32
|
||||
REG_L a0, 56($12) # cif
|
||||
REG_L a1, 64($12) # fun
|
||||
REG_L a2, 72($12) # user_data
|
||||
ADDU a3, $sp, V0_OFF2
|
||||
ADDU a4, $sp, A0_OFF2
|
||||
ADDU a5, $sp, F12_OFF2
|
||||
|
||||
$do_closure:
|
||||
# Store all possible argument registers. If there are more than
|
||||
# fit in registers, then they were stored on the stack.
|
||||
REG_S a6, A6_OFF2($sp)
|
||||
REG_S a7, A7_OFF2($sp)
|
||||
|
||||
#ifndef __mips_soft_float
|
||||
# Store all possible float/double registers.
|
||||
s.d $f12, F12_OFF2($sp)
|
||||
s.d $f13, F13_OFF2($sp)
|
||||
|
@ -440,13 +508,8 @@ ffi_closure_N32:
|
|||
s.d $f17, F17_OFF2($sp)
|
||||
s.d $f18, F18_OFF2($sp)
|
||||
s.d $f19, F19_OFF2($sp)
|
||||
#endif
|
||||
|
||||
# Call ffi_closure_mips_inner_N32 to do the real work.
|
||||
LA t9, ffi_closure_mips_inner_N32
|
||||
move a0, $12 # Pointer to the ffi_closure
|
||||
ADDU a1, $sp, V0_OFF2
|
||||
ADDU a2, $sp, A0_OFF2
|
||||
ADDU a3, $sp, F12_OFF2
|
||||
jalr t9
|
||||
|
||||
# Return flags are in v0
|
||||
|
@ -460,6 +523,7 @@ cls_retint:
|
|||
b cls_epilogue
|
||||
|
||||
cls_retfloat:
|
||||
#ifndef __mips_soft_float
|
||||
bne v0, FFI_TYPE_FLOAT, cls_retdouble
|
||||
l.s $f0, V0_OFF2($sp)
|
||||
b cls_epilogue
|
||||
|
@ -502,6 +566,7 @@ cls_retstruct_f_d:
|
|||
l.s $f0, V0_OFF2($sp)
|
||||
l.d $f2, V1_OFF2($sp)
|
||||
b cls_epilogue
|
||||
#endif
|
||||
|
||||
cls_retstruct_small2:
|
||||
REG_L v0, V0_OFF2($sp)
|
||||
|
@ -517,7 +582,7 @@ cls_epilogue:
|
|||
.end ffi_closure_N32
|
||||
|
||||
#ifdef __GNUC__
|
||||
.section .eh_frame,"aw",@progbits
|
||||
.section .eh_frame,EH_FRAME_FLAGS,@progbits
|
||||
.Lframe1:
|
||||
.4byte .LECIE1-.LSCIE1 # length
|
||||
.LSCIE1:
|
||||
|
@ -533,46 +598,66 @@ cls_epilogue:
|
|||
.align EH_FRAME_ALIGN
|
||||
.LECIE1:
|
||||
|
||||
.LSFDE1:
|
||||
.4byte .LEFDE1-.LASFDE1 # length.
|
||||
.LASFDE1:
|
||||
.4byte .LASFDE1-.Lframe1 # CIE_pointer.
|
||||
FDE_ADDR_BYTES .LFB3 # initial_location.
|
||||
FDE_ADDR_BYTES .LFE3-.LFB3 # address_range.
|
||||
.LSFDE0:
|
||||
.4byte .LEFDE0-.LASFDE0 # length.
|
||||
.LASFDE0:
|
||||
.4byte .LASFDE0-.Lframe1 # CIE_pointer.
|
||||
FDE_ADDR_BYTES .LFB0 # initial_location.
|
||||
FDE_ADDR_BYTES .LFE0-.LFB0 # address_range.
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte .LCFI0-.LFB3 # to .LCFI0
|
||||
.4byte .LCFI00-.LFB0 # to .LCFI00
|
||||
.byte 0xe # DW_CFA_def_cfa_offset
|
||||
.uleb128 SIZEOF_FRAME # adjust stack.by SIZEOF_FRAME
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte .LCFI1-.LCFI0 # to .LCFI1
|
||||
.4byte .LCFI01-.LCFI00 # to .LCFI01
|
||||
.byte 0x9e # DW_CFA_offset of $fp
|
||||
.uleb128 2*FFI_SIZEOF_ARG/4 #
|
||||
.byte 0x9f # DW_CFA_offset of ra
|
||||
.uleb128 1*FFI_SIZEOF_ARG/4 #
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte .LCFI3-.LCFI1 # to .LCFI3
|
||||
.4byte .LCFI02-.LCFI01 # to .LCFI02
|
||||
.byte 0xd # DW_CFA_def_cfa_register
|
||||
.uleb128 0x1e # in $fp
|
||||
.align EH_FRAME_ALIGN
|
||||
.LEFDE1:
|
||||
.LSFDE3:
|
||||
.4byte .LEFDE3-.LASFDE3 # length
|
||||
.LASFDE3:
|
||||
.4byte .LASFDE3-.Lframe1 # CIE_pointer.
|
||||
FDE_ADDR_BYTES .LFB2 # initial_location.
|
||||
FDE_ADDR_BYTES .LFE2-.LFB2 # address_range.
|
||||
.LEFDE0:
|
||||
|
||||
.LSFDE1:
|
||||
.4byte .LEFDE1-.LASFDE1 # length
|
||||
.LASFDE1:
|
||||
.4byte .LASFDE1-.Lframe1 # CIE_pointer.
|
||||
FDE_ADDR_BYTES .LFB1 # initial_location.
|
||||
FDE_ADDR_BYTES .LFE1-.LFB1 # address_range.
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte .LCFI5-.LFB2 # to .LCFI5
|
||||
.4byte .LCFI10-.LFB1 # to .LCFI10
|
||||
.byte 0xe # DW_CFA_def_cfa_offset
|
||||
.uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte .LCFI6-.LCFI5 # to .LCFI6
|
||||
.4byte .LCFI11-.LCFI10 # to .LCFI11
|
||||
.byte 0x9c # DW_CFA_offset of $gp ($28)
|
||||
.uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
|
||||
.byte 0x9f # DW_CFA_offset of ra ($31)
|
||||
.uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
|
||||
.align EH_FRAME_ALIGN
|
||||
.LEFDE3:
|
||||
.LEFDE1:
|
||||
|
||||
.LSFDE2:
|
||||
.4byte .LEFDE2-.LASFDE2 # length
|
||||
.LASFDE2:
|
||||
.4byte .LASFDE2-.Lframe1 # CIE_pointer.
|
||||
FDE_ADDR_BYTES .LFB2 # initial_location.
|
||||
FDE_ADDR_BYTES .LFE2-.LFB2 # address_range.
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte .LCFI20-.LFB2 # to .LCFI20
|
||||
.byte 0xe # DW_CFA_def_cfa_offset
|
||||
.uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte .LCFI21-.LCFI20 # to .LCFI21
|
||||
.byte 0x9c # DW_CFA_offset of $gp ($28)
|
||||
.uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
|
||||
.byte 0x9f # DW_CFA_offset of ra ($31)
|
||||
.uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
|
||||
.align EH_FRAME_ALIGN
|
||||
.LEFDE2:
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -50,14 +50,14 @@ ffi_call_O32:
|
|||
$LFB0:
|
||||
# Prologue
|
||||
SUBU $sp, SIZEOF_FRAME # Frame size
|
||||
$LCFI0:
|
||||
$LCFI00:
|
||||
REG_S $fp, FP_OFF($sp) # Save frame pointer
|
||||
$LCFI1:
|
||||
$LCFI01:
|
||||
REG_S ra, RA_OFF($sp) # Save return address
|
||||
$LCFI2:
|
||||
$LCFI02:
|
||||
move $fp, $sp
|
||||
|
||||
$LCFI3:
|
||||
$LCFI03:
|
||||
move t9, callback # callback function pointer
|
||||
REG_S flags, A3_OFF($fp) # flags
|
||||
|
||||
|
@ -82,13 +82,16 @@ sixteen:
|
|||
|
||||
ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
|
||||
|
||||
#ifndef __mips_soft_float
|
||||
bnez t0, pass_d # make it quick for int
|
||||
#endif
|
||||
REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
|
||||
REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
|
||||
REG_L a2, 2*FFI_SIZEOF_ARG($sp)
|
||||
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
|
||||
b call_it
|
||||
|
||||
#ifndef __mips_soft_float
|
||||
pass_d:
|
||||
bne t0, FFI_ARGS_D, pass_f
|
||||
l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
|
||||
|
@ -130,8 +133,12 @@ pass_f_d:
|
|||
# bne t0, FFI_ARGS_F_D, call_it
|
||||
l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
|
||||
l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
|
||||
#endif
|
||||
|
||||
call_it:
|
||||
# Load the static chain pointer
|
||||
REG_L t7, SIZEOF_FRAME + 6*FFI_SIZEOF_ARG($fp)
|
||||
|
||||
# Load the function pointer
|
||||
REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
|
||||
|
||||
|
@ -158,14 +165,23 @@ retfloat:
|
|||
bne t2, FFI_TYPE_FLOAT, retdouble
|
||||
jalr t9
|
||||
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
|
||||
#ifndef __mips_soft_float
|
||||
s.s $f0, 0(t0)
|
||||
#else
|
||||
REG_S v0, 0(t0)
|
||||
#endif
|
||||
b epilogue
|
||||
|
||||
retdouble:
|
||||
bne t2, FFI_TYPE_DOUBLE, noretval
|
||||
jalr t9
|
||||
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
|
||||
#ifndef __mips_soft_float
|
||||
s.d $f0, 0(t0)
|
||||
#else
|
||||
REG_S v1, 4(t0)
|
||||
REG_S v0, 0(t0)
|
||||
#endif
|
||||
b epilogue
|
||||
|
||||
noretval:
|
||||
|
@ -204,13 +220,15 @@ $LFE0:
|
|||
-8 - f14 (le low, be high)
|
||||
-9 - f12 (le high, be low)
|
||||
-10 - f12 (le low, be high)
|
||||
-11 - Called function a3 save
|
||||
-12 - Called function a2 save
|
||||
-13 - Called function a1 save
|
||||
-14 - Called function a0 save, our sp and fp point here
|
||||
-11 - Called function a5 save
|
||||
-12 - Called function a4 save
|
||||
-13 - Called function a3 save
|
||||
-14 - Called function a2 save
|
||||
-15 - Called function a1 save
|
||||
-16 - Called function a0 save, our sp and fp point here
|
||||
*/
|
||||
|
||||
#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
|
||||
#define SIZEOF_FRAME2 (16 * FFI_SIZEOF_ARG)
|
||||
#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
|
||||
#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
|
||||
#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
|
||||
|
@ -225,12 +243,15 @@ $LFE0:
|
|||
#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
|
||||
#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
|
||||
#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
|
||||
#define CALLED_A5_OFF2 (SIZEOF_FRAME2 - 11 * FFI_SIZEOF_ARG)
|
||||
#define CALLED_A4_OFF2 (SIZEOF_FRAME2 - 12 * FFI_SIZEOF_ARG)
|
||||
|
||||
.text
|
||||
|
||||
.align 2
|
||||
.globl ffi_closure_O32
|
||||
.ent ffi_closure_O32
|
||||
ffi_closure_O32:
|
||||
.globl ffi_go_closure_O32
|
||||
.ent ffi_go_closure_O32
|
||||
ffi_go_closure_O32:
|
||||
$LFB1:
|
||||
# Prologue
|
||||
.frame $fp, SIZEOF_FRAME2, ra
|
||||
|
@ -239,14 +260,71 @@ $LFB1:
|
|||
.set reorder
|
||||
SUBU $sp, SIZEOF_FRAME2
|
||||
.cprestore GP_OFF2
|
||||
$LCFI4:
|
||||
$LCFI10:
|
||||
|
||||
REG_S $16, S0_OFF2($sp) # Save s0
|
||||
REG_S $fp, FP_OFF2($sp) # Save frame pointer
|
||||
REG_S ra, RA_OFF2($sp) # Save return address
|
||||
$LCFI6:
|
||||
$LCFI11:
|
||||
|
||||
move $fp, $sp
|
||||
$LCFI12:
|
||||
|
||||
REG_S a0, A0_OFF2($fp)
|
||||
REG_S a1, A1_OFF2($fp)
|
||||
REG_S a2, A2_OFF2($fp)
|
||||
REG_S a3, A3_OFF2($fp)
|
||||
|
||||
# Load ABI enum to s0
|
||||
REG_L $16, 4($15) # cif
|
||||
REG_L $16, 0($16) # abi is first member.
|
||||
|
||||
li $13, 1 # FFI_O32
|
||||
bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
|
||||
|
||||
#ifndef __mips_soft_float
|
||||
# Store all possible float/double registers.
|
||||
s.d $f12, FA_0_0_OFF2($fp)
|
||||
s.d $f14, FA_1_0_OFF2($fp)
|
||||
#endif
|
||||
1:
|
||||
# prepare arguments for ffi_closure_mips_inner_O32
|
||||
REG_L a0, 4($15) # cif
|
||||
REG_L a1, 8($15) # fun
|
||||
move a2, $15 # user_data = go closure
|
||||
addu a3, $fp, V0_OFF2 # rvalue
|
||||
|
||||
addu t9, $fp, A0_OFF2 # ar
|
||||
REG_S t9, CALLED_A4_OFF2($fp)
|
||||
|
||||
addu t9, $fp, FA_0_0_OFF2 #fpr
|
||||
REG_S t9, CALLED_A5_OFF2($fp)
|
||||
|
||||
b $do_closure
|
||||
|
||||
$LFE1:
|
||||
.end ffi_go_closure_O32
|
||||
|
||||
.align 2
|
||||
.globl ffi_closure_O32
|
||||
.ent ffi_closure_O32
|
||||
ffi_closure_O32:
|
||||
$LFB2:
|
||||
# Prologue
|
||||
.frame $fp, SIZEOF_FRAME2, ra
|
||||
.set noreorder
|
||||
.cpload t9
|
||||
.set reorder
|
||||
SUBU $sp, SIZEOF_FRAME2
|
||||
.cprestore GP_OFF2
|
||||
$LCFI20:
|
||||
REG_S $16, S0_OFF2($sp) # Save s0
|
||||
REG_S $fp, FP_OFF2($sp) # Save frame pointer
|
||||
REG_S ra, RA_OFF2($sp) # Save return address
|
||||
$LCFI21:
|
||||
move $fp, $sp
|
||||
|
||||
$LCFI7:
|
||||
$LCFI22:
|
||||
# Store all possible argument registers. If there are more than
|
||||
# four arguments, then they are stored above where we put a3.
|
||||
REG_S a0, A0_OFF2($fp)
|
||||
|
@ -261,16 +339,27 @@ $LCFI7:
|
|||
li $13, 1 # FFI_O32
|
||||
bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
|
||||
|
||||
#ifndef __mips_soft_float
|
||||
# Store all possible float/double registers.
|
||||
s.d $f12, FA_0_0_OFF2($fp)
|
||||
s.d $f14, FA_1_0_OFF2($fp)
|
||||
#endif
|
||||
1:
|
||||
# Call ffi_closure_mips_inner_O32 to do the work.
|
||||
# prepare arguments for ffi_closure_mips_inner_O32
|
||||
REG_L a0, 20($12) # cif pointer follows tramp.
|
||||
REG_L a1, 24($12) # fun
|
||||
REG_L a2, 28($12) # user_data
|
||||
addu a3, $fp, V0_OFF2 # rvalue
|
||||
|
||||
addu t9, $fp, A0_OFF2 # ar
|
||||
REG_S t9, CALLED_A4_OFF2($fp)
|
||||
|
||||
addu t9, $fp, FA_0_0_OFF2 #fpr
|
||||
REG_S t9, CALLED_A5_OFF2($fp)
|
||||
|
||||
$do_closure:
|
||||
la t9, ffi_closure_mips_inner_O32
|
||||
move a0, $12 # Pointer to the ffi_closure
|
||||
addu a1, $fp, V0_OFF2
|
||||
addu a2, $fp, A0_OFF2
|
||||
addu a3, $fp, FA_0_0_OFF2
|
||||
# Call ffi_closure_mips_inner_O32 to do the work.
|
||||
jalr t9
|
||||
|
||||
# Load the return value into the appropriate register.
|
||||
|
@ -281,6 +370,7 @@ $LCFI7:
|
|||
li $13, 1 # FFI_O32
|
||||
bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
|
||||
|
||||
#ifndef __mips_soft_float
|
||||
li $9, FFI_TYPE_FLOAT
|
||||
l.s $f0, V0_OFF2($fp)
|
||||
beq $8, $9, closure_done
|
||||
|
@ -288,6 +378,7 @@ $LCFI7:
|
|||
li $9, FFI_TYPE_DOUBLE
|
||||
l.d $f0, V0_OFF2($fp)
|
||||
beq $8, $9, closure_done
|
||||
#endif
|
||||
1:
|
||||
REG_L $3, V1_OFF2($fp)
|
||||
REG_L $2, V0_OFF2($fp)
|
||||
|
@ -300,7 +391,7 @@ closure_done:
|
|||
REG_L ra, RA_OFF2($sp) # Restore return address
|
||||
ADDU $sp, SIZEOF_FRAME2
|
||||
j ra
|
||||
$LFE1:
|
||||
$LFE2:
|
||||
.end ffi_closure_O32
|
||||
|
||||
/* DWARF-2 unwind info. */
|
||||
|
@ -322,6 +413,7 @@ $LSCIE0:
|
|||
.uleb128 0x0
|
||||
.align 2
|
||||
$LECIE0:
|
||||
|
||||
$LSFDE0:
|
||||
.4byte $LEFDE0-$LASFDE0 # FDE Length
|
||||
$LASFDE0:
|
||||
|
@ -330,11 +422,11 @@ $LASFDE0:
|
|||
.4byte $LFE0-$LFB0 # FDE address range
|
||||
.uleb128 0x0 # Augmentation size
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI0-$LFB0
|
||||
.4byte $LCFI00-$LFB0
|
||||
.byte 0xe # DW_CFA_def_cfa_offset
|
||||
.uleb128 0x18
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI2-$LCFI0
|
||||
.4byte $LCFI01-$LCFI00
|
||||
.byte 0x11 # DW_CFA_offset_extended_sf
|
||||
.uleb128 0x1e # $fp
|
||||
.sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
|
||||
|
@ -342,12 +434,13 @@ $LASFDE0:
|
|||
.uleb128 0x1f # $ra
|
||||
.sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI3-$LCFI2
|
||||
.4byte $LCFI02-$LCFI01
|
||||
.byte 0xc # DW_CFA_def_cfa
|
||||
.uleb128 0x1e
|
||||
.uleb128 0x18
|
||||
.align 2
|
||||
$LEFDE0:
|
||||
|
||||
$LSFDE1:
|
||||
.4byte $LEFDE1-$LASFDE1 # FDE Length
|
||||
$LASFDE1:
|
||||
|
@ -356,11 +449,11 @@ $LASFDE1:
|
|||
.4byte $LFE1-$LFB1 # FDE address range
|
||||
.uleb128 0x0 # Augmentation size
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI4-$LFB1
|
||||
.4byte $LCFI10-$LFB1
|
||||
.byte 0xe # DW_CFA_def_cfa_offset
|
||||
.uleb128 0x38
|
||||
.uleb128 SIZEOF_FRAME2
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI6-$LCFI4
|
||||
.4byte $LCFI11-$LCFI10
|
||||
.byte 0x11 # DW_CFA_offset_extended_sf
|
||||
.uleb128 0x10 # $16
|
||||
.sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
|
||||
|
@ -371,11 +464,41 @@ $LASFDE1:
|
|||
.uleb128 0x1f # $ra
|
||||
.sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI7-$LCFI6
|
||||
.4byte $LCFI12-$LCFI11
|
||||
.byte 0xc # DW_CFA_def_cfa
|
||||
.uleb128 0x1e
|
||||
.uleb128 0x38
|
||||
.uleb128 SIZEOF_FRAME2
|
||||
.align 2
|
||||
$LEFDE1:
|
||||
|
||||
$LSFDE2:
|
||||
.4byte $LEFDE2-$LASFDE2 # FDE Length
|
||||
$LASFDE2:
|
||||
.4byte $LASFDE2-$Lframe0 # FDE CIE offset
|
||||
.4byte $LFB2 # FDE initial location
|
||||
.4byte $LFE2-$LFB2 # FDE address range
|
||||
.uleb128 0x0 # Augmentation size
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI20-$LFB2
|
||||
.byte 0xe # DW_CFA_def_cfa_offset
|
||||
.uleb128 SIZEOF_FRAME2
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI21-$LCFI20
|
||||
.byte 0x11 # DW_CFA_offset_extended_sf
|
||||
.uleb128 0x10 # $16
|
||||
.sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
|
||||
.byte 0x11 # DW_CFA_offset_extended_sf
|
||||
.uleb128 0x1e # $fp
|
||||
.sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
|
||||
.byte 0x11 # DW_CFA_offset_extended_sf
|
||||
.uleb128 0x1f # $ra
|
||||
.sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
|
||||
.byte 0x4 # DW_CFA_advance_loc4
|
||||
.4byte $LCFI22-$LCFI21
|
||||
.byte 0xc # DW_CFA_def_cfa
|
||||
.uleb128 0x1e
|
||||
.uleb128 SIZEOF_FRAME2
|
||||
.align 2
|
||||
$LEFDE2:
|
||||
|
||||
#endif
|
||||
|
|
|
@ -59,7 +59,7 @@ ffi_call_EABI:
|
|||
mov $r6, $r4 /* Save result buffer */
|
||||
mov $r7, $r5 /* Save the target fn */
|
||||
mov $r8, $r3 /* Save the flags */
|
||||
sub.l $sp, $r2 /* Allocate stack space */
|
||||
sub $sp, $r2 /* Allocate stack space */
|
||||
mov $r0, $sp /* We can stomp over $r0 */
|
||||
/* $r1 is already set up */
|
||||
jsra ffi_prep_args
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (C) 2012, 2013 Anthony Green
|
||||
ffi.c - Copyright (C) 2012, 2013, 2018 Anthony Green
|
||||
|
||||
Moxie Foreign Function Interface
|
||||
|
||||
|
@ -100,7 +100,7 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
|
|||
count += z;
|
||||
}
|
||||
|
||||
return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
|
||||
return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
|
@ -111,7 +111,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
else
|
||||
cif->flags = cif->rtype->size;
|
||||
|
||||
cif->bytes = ALIGN (cif->bytes, 8);
|
||||
cif->bytes = FFI_ALIGN (cif->bytes, 8);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
|
|||
unsigned arg4, unsigned arg5, unsigned arg6)
|
||||
{
|
||||
/* This function is called by a trampoline. The trampoline stows a
|
||||
pointer to the ffi_closure object in $r7. We must save this
|
||||
pointer to the ffi_closure object in $r12. We must save this
|
||||
pointer in a place that will persist while we do our work. */
|
||||
register ffi_closure *creg __asm__ ("$r12");
|
||||
ffi_closure *closure = creg;
|
||||
|
@ -215,7 +215,18 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
|
|||
break;
|
||||
default:
|
||||
/* This is an 8-byte value. */
|
||||
avalue[i] = ptr;
|
||||
if (ptr == (char *) ®ister_args[5])
|
||||
{
|
||||
/* The value is split across two locations */
|
||||
unsigned *ip = alloca(8);
|
||||
avalue[i] = ip;
|
||||
ip[0] = *(unsigned *) ptr;
|
||||
ip[1] = *(unsigned *) stack_args;
|
||||
}
|
||||
else
|
||||
{
|
||||
avalue[i] = ptr;
|
||||
}
|
||||
ptr += 4;
|
||||
break;
|
||||
}
|
||||
|
@ -223,8 +234,10 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
|
|||
|
||||
/* If we've handled more arguments than fit in registers,
|
||||
start looking at the those passed on the stack. */
|
||||
if (ptr == ®ister_args[6])
|
||||
if (ptr == (char *) ®ister_args[6])
|
||||
ptr = stack_args;
|
||||
else if (ptr == (char *) ®ister_args[7])
|
||||
ptr = stack_args + 4;
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
|
@ -257,7 +270,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||
|
||||
fn = (unsigned long) ffi_closure_eabi;
|
||||
|
||||
tramp[0] = 0x01e0; /* ldi.l $r7, .... */
|
||||
tramp[0] = 0x01e0; /* ldi.l $r12, .... */
|
||||
tramp[1] = cls >> 16;
|
||||
tramp[2] = cls & 0xffff;
|
||||
tramp[3] = 0x1a00; /* jmpa .... */
|
||||
|
|
|
@ -101,7 +101,7 @@ void ffi_prep_args (char *stack, extended_cif *ecif)
|
|||
|
||||
/* Align argp as appropriate for the argument type. */
|
||||
if ((alignment - 1) & (unsigned) argp)
|
||||
argp = (char *) ALIGN (argp, alignment);
|
||||
argp = (char *) FFI_ALIGN (argp, alignment);
|
||||
|
||||
/* Copy the argument, promoting integral types smaller than a
|
||||
word to word size. */
|
||||
|
@ -230,7 +230,7 @@ ffi_closure_helper (unsigned char *args,
|
|||
|
||||
/* Align argp as appropriate for the argument type. */
|
||||
if ((alignment - 1) & (unsigned) argp)
|
||||
argp = (char *) ALIGN (argp, alignment);
|
||||
argp = (char *) FFI_ALIGN (argp, alignment);
|
||||
|
||||
/* Arguments smaller than an int are promoted to int. */
|
||||
if (size < sizeof (int))
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi.c - (c) 2016 John David Anglin
|
||||
(c) 2011 Anthony Green
|
||||
ffi.c - (c) 2011 Anthony Green
|
||||
(c) 2008 Red Hat, Inc.
|
||||
(c) 2006 Free Software Foundation, Inc.
|
||||
(c) 2003-2004 Randolph Chung <tausq@debian.org>
|
||||
|
@ -52,8 +51,7 @@
|
|||
|
||||
#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
|
||||
|
||||
static inline int
|
||||
ffi_struct_type (ffi_type *t)
|
||||
static inline int ffi_struct_type(ffi_type *t)
|
||||
{
|
||||
size_t sz = t->size;
|
||||
|
||||
|
@ -141,8 +139,7 @@ ffi_struct_type (ffi_type *t)
|
|||
NOTE: We load floating point args in this function... that means we
|
||||
assume gcc will not mess with fp regs in here. */
|
||||
|
||||
void
|
||||
ffi_prep_args_pa32 (UINT32 *stack, extended_cif *ecif, unsigned bytes)
|
||||
void ffi_prep_args_pa32(UINT32 *stack, extended_cif *ecif, unsigned bytes)
|
||||
{
|
||||
register unsigned int i;
|
||||
register ffi_type **p_arg;
|
||||
|
@ -278,8 +275,7 @@ ffi_prep_args_pa32 (UINT32 *stack, extended_cif *ecif, unsigned bytes)
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_size_stack_pa32 (ffi_cif *cif)
|
||||
static void ffi_size_stack_pa32(ffi_cif *cif)
|
||||
{
|
||||
ffi_type **ptr;
|
||||
int i;
|
||||
|
@ -320,8 +316,7 @@ ffi_size_stack_pa32 (ffi_cif *cif)
|
|||
}
|
||||
|
||||
/* Perform machine dependent cif processing. */
|
||||
ffi_status
|
||||
ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
/* Set the return type flag */
|
||||
switch (cif->rtype->type)
|
||||
|
@ -374,13 +369,11 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
extern void ffi_call_pa32 (void (*)(UINT32 *, extended_cif *, unsigned),
|
||||
extended_cif *, unsigned, unsigned, unsigned *,
|
||||
void (*fn)(void), void *closure);
|
||||
extern void ffi_call_pa32(void (*)(UINT32 *, extended_cif *, unsigned),
|
||||
extended_cif *, unsigned, unsigned, unsigned *,
|
||||
void (*fn)(void));
|
||||
|
||||
static void
|
||||
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue,
|
||||
void *closure)
|
||||
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
extended_cif ecif;
|
||||
|
||||
|
@ -408,8 +401,8 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue,
|
|||
{
|
||||
case FFI_PA32:
|
||||
debug(3, "Calling ffi_call_pa32: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
|
||||
ffi_call_pa32 (ffi_prep_args_pa32, &ecif, cif->bytes,
|
||||
cif->flags, ecif.rvalue, fn, closure);
|
||||
ffi_call_pa32(ffi_prep_args_pa32, &ecif, cif->bytes,
|
||||
cif->flags, ecif.rvalue, fn);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -418,60 +411,35 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue,
|
||||
void *closure)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, closure);
|
||||
}
|
||||
|
||||
#if FFI_CLOSURES
|
||||
/* This is more-or-less an inverse of ffi_call -- we have arguments on
|
||||
the stack, and we need to fill them into a cif structure and invoke
|
||||
the user function. This really ought to be in asm to make sure
|
||||
the compiler doesn't do things we don't expect. */
|
||||
ffi_status
|
||||
ffi_closure_inner_pa32 (void *closure, UINT32 *stack, int closure_type)
|
||||
ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
void (*fun)(ffi_cif *,void *,void **,void *);
|
||||
void *user_data;
|
||||
void **avalue;
|
||||
void *rvalue;
|
||||
UINT32 ret[2]; /* function can return up to 64-bits in registers */
|
||||
/* Functions can return up to 64-bits in registers. Return address
|
||||
must be double word aligned. */
|
||||
union { double rd; UINT32 ret[2]; } u;
|
||||
ffi_type **p_arg;
|
||||
char *tmp;
|
||||
int i, avn;
|
||||
unsigned int slot = FIRST_ARG_SLOT;
|
||||
register UINT32 r28 asm("r28");
|
||||
ffi_closure *c = (ffi_closure *)FFI_RESTORE_PTR (closure);
|
||||
|
||||
/* A non-zero closure type indicates a go closure. */
|
||||
if (closure_type)
|
||||
{
|
||||
cif = ((ffi_go_closure *)closure)->cif;
|
||||
fun = ((ffi_go_closure *)closure)->fun;
|
||||
user_data = closure;
|
||||
}
|
||||
else
|
||||
{
|
||||
cif = ((ffi_closure *)closure)->cif;
|
||||
fun = ((ffi_closure *)closure)->fun;
|
||||
user_data = ((ffi_closure *)closure)->user_data;
|
||||
}
|
||||
cif = closure->cif;
|
||||
|
||||
/* If returning via structure, callee will write to our pointer. */
|
||||
if (cif->flags == FFI_TYPE_STRUCT)
|
||||
rvalue = (void *)r28;
|
||||
else
|
||||
rvalue = &ret[0];
|
||||
rvalue = &u;
|
||||
|
||||
avalue = (void **) alloca (cif->nargs * FFI_SIZEOF_ARG);
|
||||
avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG);
|
||||
avn = cif->nargs;
|
||||
p_arg = cif->arg_types;
|
||||
|
||||
|
@ -564,35 +532,35 @@ ffi_closure_inner_pa32 (void *closure, UINT32 *stack, int closure_type)
|
|||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
fun (cif, rvalue, avalue, user_data);
|
||||
(c->fun) (cif, rvalue, avalue, c->user_data);
|
||||
|
||||
debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0],
|
||||
ret[1]);
|
||||
debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", u.ret[0],
|
||||
u.ret[1]);
|
||||
|
||||
/* Store the result using the lower 2 bytes of the flags. */
|
||||
switch (cif->flags)
|
||||
{
|
||||
case FFI_TYPE_UINT8:
|
||||
*(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
|
||||
*(stack - FIRST_ARG_SLOT) = (UINT8)(u.ret[0] >> 24);
|
||||
break;
|
||||
case FFI_TYPE_SINT8:
|
||||
*(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
|
||||
*(stack - FIRST_ARG_SLOT) = (SINT8)(u.ret[0] >> 24);
|
||||
break;
|
||||
case FFI_TYPE_UINT16:
|
||||
*(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
|
||||
*(stack - FIRST_ARG_SLOT) = (UINT16)(u.ret[0] >> 16);
|
||||
break;
|
||||
case FFI_TYPE_SINT16:
|
||||
*(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
|
||||
*(stack - FIRST_ARG_SLOT) = (SINT16)(u.ret[0] >> 16);
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
*(stack - FIRST_ARG_SLOT) = ret[0];
|
||||
*(stack - FIRST_ARG_SLOT) = u.ret[0];
|
||||
break;
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
*(stack - FIRST_ARG_SLOT) = ret[0];
|
||||
*(stack - FIRST_ARG_SLOT - 1) = ret[1];
|
||||
*(stack - FIRST_ARG_SLOT) = u.ret[0];
|
||||
*(stack - FIRST_ARG_SLOT - 1) = u.ret[1];
|
||||
break;
|
||||
|
||||
case FFI_TYPE_DOUBLE:
|
||||
|
@ -612,7 +580,7 @@ ffi_closure_inner_pa32 (void *closure, UINT32 *stack, int closure_type)
|
|||
case FFI_TYPE_SMALL_STRUCT4:
|
||||
tmp = (void*)(stack - FIRST_ARG_SLOT);
|
||||
tmp += 4 - cif->rtype->size;
|
||||
memcpy((void*)tmp, &ret[0], cif->rtype->size);
|
||||
memcpy((void*)tmp, &u, cif->rtype->size);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SMALL_STRUCT5:
|
||||
|
@ -633,7 +601,7 @@ ffi_closure_inner_pa32 (void *closure, UINT32 *stack, int closure_type)
|
|||
}
|
||||
|
||||
memset (ret2, 0, sizeof (ret2));
|
||||
memcpy ((char *)ret2 + off, ret, 8 - off);
|
||||
memcpy ((char *)ret2 + off, &u, 8 - off);
|
||||
|
||||
*(stack - FIRST_ARG_SLOT) = ret2[0];
|
||||
*(stack - FIRST_ARG_SLOT - 1) = ret2[1];
|
||||
|
@ -656,7 +624,6 @@ ffi_closure_inner_pa32 (void *closure, UINT32 *stack, int closure_type)
|
|||
cif specifies the argument and result types for fun.
|
||||
The cif must already be prep'ed. */
|
||||
|
||||
extern void ffi_go_closure_pa32(void);
|
||||
extern void ffi_closure_pa32(void);
|
||||
|
||||
ffi_status
|
||||
|
@ -666,107 +633,42 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
UINT32 *tramp = (UINT32 *)(closure->tramp);
|
||||
#ifdef PA_HPUX
|
||||
UINT32 *tmp;
|
||||
#endif
|
||||
ffi_closure *c = (ffi_closure *)FFI_RESTORE_PTR (closure);
|
||||
|
||||
/* The layout of a function descriptor. A function pointer with the PLABEL
|
||||
bit set points to a function descriptor. */
|
||||
struct pa32_fd
|
||||
{
|
||||
UINT32 code_pointer;
|
||||
UINT32 gp;
|
||||
};
|
||||
|
||||
struct ffi_pa32_trampoline_struct
|
||||
{
|
||||
UINT32 code_pointer; /* Pointer to ffi_closure_unix. */
|
||||
UINT32 fake_gp; /* Pointer to closure, installed as gp. */
|
||||
UINT32 real_gp; /* Real gp value. */
|
||||
};
|
||||
|
||||
struct ffi_pa32_trampoline_struct *tramp;
|
||||
struct pa32_fd *fd;
|
||||
|
||||
if (cif->abi != FFI_PA32)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
/* Make a small trampoline that will branch to our
|
||||
handler function. Use PC-relative addressing. */
|
||||
/* Get function descriptor address for ffi_closure_pa32. */
|
||||
fd = (struct pa32_fd *)((UINT32)ffi_closure_pa32 & ~3);
|
||||
|
||||
#ifdef PA_LINUX
|
||||
tramp[0] = 0xeaa00000; /* b,l .+8,%r21 ; %r21 <- pc+8 */
|
||||
tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21 ; mask priv bits */
|
||||
tramp[2] = 0x4aa10028; /* ldw 20(%r21),%r1 ; load plabel */
|
||||
tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21 ; get closure addr */
|
||||
tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22 ; address of handler */
|
||||
tramp[5] = 0xeac0c000; /* bv%r0(%r22) ; branch to handler */
|
||||
tramp[6] = 0x0c281093; /* ldw 4(%r1),%r19 ; GP of handler */
|
||||
tramp[7] = ((UINT32)(ffi_closure_pa32) & ~2);
|
||||
/* Setup trampoline. */
|
||||
tramp = (struct ffi_pa32_trampoline_struct *)c->tramp;
|
||||
tramp->code_pointer = fd->code_pointer;
|
||||
tramp->fake_gp = (UINT32)codeloc & ~3;
|
||||
tramp->real_gp = fd->gp;
|
||||
|
||||
/* Flush d/icache -- have to flush up 2 two lines because of
|
||||
alignment. */
|
||||
__asm__ volatile(
|
||||
"fdc 0(%0)\n\t"
|
||||
"fdc %1(%0)\n\t"
|
||||
"fic 0(%%sr4, %0)\n\t"
|
||||
"fic %1(%%sr4, %0)\n\t"
|
||||
"sync\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n"
|
||||
:
|
||||
: "r"((unsigned long)tramp & ~31),
|
||||
"r"(32 /* stride */)
|
||||
: "memory");
|
||||
#endif
|
||||
|
||||
#ifdef PA_HPUX
|
||||
tramp[0] = 0xeaa00000; /* b,l .+8,%r21 ; %r21 <- pc+8 */
|
||||
tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21 ; mask priv bits */
|
||||
tramp[2] = 0x4aa10038; /* ldw 28(%r21),%r1 ; load plabel */
|
||||
tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21 ; get closure addr */
|
||||
tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22 ; address of handler */
|
||||
tramp[5] = 0x02c010b4; /* ldsid (%r22),%r20 ; load space id */
|
||||
tramp[6] = 0x00141820; /* mtsp %r20,%sr0 ; into %sr0 */
|
||||
tramp[7] = 0xe2c00000; /* be 0(%sr0,%r22) ; branch to handler */
|
||||
tramp[8] = 0x0c281093; /* ldw 4(%r1),%r19 ; GP of handler */
|
||||
tramp[9] = ((UINT32)(ffi_closure_pa32) & ~2);
|
||||
|
||||
/* Flush d/icache -- have to flush three lines because of alignment. */
|
||||
__asm__ volatile(
|
||||
"copy %1,%0\n\t"
|
||||
"fdc,m %2(%0)\n\t"
|
||||
"fdc,m %2(%0)\n\t"
|
||||
"fdc,m %2(%0)\n\t"
|
||||
"ldsid (%1),%0\n\t"
|
||||
"mtsp %0,%%sr0\n\t"
|
||||
"copy %1,%0\n\t"
|
||||
"fic,m %2(%%sr0,%0)\n\t"
|
||||
"fic,m %2(%%sr0,%0)\n\t"
|
||||
"fic,m %2(%%sr0,%0)\n\t"
|
||||
"sync\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n"
|
||||
: "=&r" ((unsigned long)tmp)
|
||||
: "r" ((unsigned long)tramp & ~31),
|
||||
"r" (32/* stride */)
|
||||
: "memory");
|
||||
#endif
|
||||
|
||||
closure->cif = cif;
|
||||
closure->user_data = user_data;
|
||||
closure->fun = fun;
|
||||
c->cif = cif;
|
||||
c->user_data = user_data;
|
||||
c->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure *closure,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif *, void *, void **, void *))
|
||||
{
|
||||
if (cif->abi != FFI_PA32)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
closure->tramp = &ffi_go_closure_pa32;
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* -----------------------------------------------------------------*-C-*-
|
||||
ffitarget.h - Copyright (c) 2016 John David Anglin
|
||||
Copyright (c) 2012 Anthony Green
|
||||
ffitarget.h - Copyright (c) 2012 Anthony Green
|
||||
Copyright (c) 1996-2003 Red Hat, Inc.
|
||||
Target configuration macros for hppa.
|
||||
|
||||
|
@ -68,14 +67,8 @@ typedef enum ffi_abi {
|
|||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_GO_CLOSURES 1
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
|
||||
#ifdef PA_LINUX
|
||||
#define FFI_TRAMPOLINE_SIZE 32
|
||||
#else
|
||||
#define FFI_TRAMPOLINE_SIZE 40
|
||||
#endif
|
||||
#define FFI_TRAMPOLINE_SIZE 12
|
||||
|
||||
#define FFI_TYPE_SMALL_STRUCT2 -1
|
||||
#define FFI_TYPE_SMALL_STRUCT3 -2
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
hpux32.S - Copyright (c) 2006 Free Software Foundation, Inc.
|
||||
(c) 2008 Red Hat, Inc.
|
||||
(c) 2016 John David Anglin
|
||||
based on src/pa/linux.S
|
||||
|
||||
HP-UX PA Foreign Function Interface
|
||||
|
@ -42,8 +41,7 @@
|
|||
unsigned bytes,
|
||||
unsigned flags,
|
||||
unsigned *rvalue,
|
||||
void (*fn)(void),
|
||||
ffi_go_closure *closure);
|
||||
void (*fn)(void));
|
||||
*/
|
||||
|
||||
.export ffi_call_pa32,ENTRY,PRIV_LEV=3
|
||||
|
@ -106,7 +104,6 @@ L$CFI13
|
|||
we need to give it a place to put the result. */
|
||||
ldw -52(%r3), %ret0 ; %ret0 <- rvalue
|
||||
ldw -56(%r3), %r22 ; %r22 <- function to call
|
||||
ldw -60(%r3), %ret1 ; %ret1 <- closure
|
||||
bl $$dyncall, %r31 ; Call the user function
|
||||
copy %r31, %rp
|
||||
|
||||
|
@ -262,7 +259,7 @@ L$done
|
|||
L$FE1
|
||||
|
||||
/* void ffi_closure_pa32(void);
|
||||
Called with closure argument in %r21 */
|
||||
Called with closure argument in %r19 */
|
||||
|
||||
.SPACE $TEXT$
|
||||
.SUBSPA $CODE$
|
||||
|
@ -288,9 +285,9 @@ L$CFI22
|
|||
stw %arg2, -44(%r3)
|
||||
stw %arg3, -48(%r3)
|
||||
|
||||
/* Closure type 0. */
|
||||
copy %r21, %arg0
|
||||
copy %r0, %arg2
|
||||
/* Retrieve closure pointer and real gp. */
|
||||
copy %r19, %arg0
|
||||
ldw 8(%r19), %r19
|
||||
bl ffi_closure_inner_pa32, %r2
|
||||
copy %r3, %arg1
|
||||
ldwm -64(%sp), %r3
|
||||
|
@ -302,47 +299,6 @@ L$CFI22
|
|||
.procend
|
||||
L$FE2:
|
||||
|
||||
/* void ffi_go_closure_pa32(void);
|
||||
Called with closure argument in %ret1 */
|
||||
|
||||
.SPACE $TEXT$
|
||||
.SUBSPA $CODE$
|
||||
.export ffi_go_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR
|
||||
.import ffi_closure_inner_pa32,CODE
|
||||
.align 4
|
||||
L$FB3
|
||||
ffi_go_closure_pa32
|
||||
.proc
|
||||
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
|
||||
.entry
|
||||
|
||||
stw %rp, -20(%sp)
|
||||
copy %r3, %r1
|
||||
L$CFI31
|
||||
copy %sp, %r3
|
||||
L$CFI32
|
||||
stwm %r1, 64(%sp)
|
||||
|
||||
/* Put arguments onto the stack and call ffi_closure_inner. */
|
||||
stw %arg0, -36(%r3)
|
||||
stw %arg1, -40(%r3)
|
||||
stw %arg2, -44(%r3)
|
||||
stw %arg3, -48(%r3)
|
||||
|
||||
/* Closure type 1. */
|
||||
copy %ret1, %arg0
|
||||
ldi 1, %arg2
|
||||
bl ffi_closure_inner_pa32, %r2
|
||||
copy %r3, %arg1
|
||||
ldwm -64(%sp), %r3
|
||||
ldw -20(%sp), %rp
|
||||
ldw -36(%sp), %ret0
|
||||
bv %r0(%rp)
|
||||
ldw -40(%sp), %ret1
|
||||
.exit
|
||||
.procend
|
||||
L$FE3:
|
||||
|
||||
.SPACE $PRIVATE$
|
||||
.SUBSPA $DATA$
|
||||
|
||||
|
@ -412,25 +368,3 @@ L$ASFDE2:
|
|||
|
||||
.align 4
|
||||
L$EFDE2:
|
||||
|
||||
L$SFDE3:
|
||||
.word L$EFDE3-L$ASFDE3 ;# FDE Length
|
||||
L$ASFDE3:
|
||||
.word L$ASFDE3-L$frame1 ;# FDE CIE offset
|
||||
.word L$FB3 ;# FDE initial location
|
||||
.word L$FE3-L$FB3 ;# FDE address range
|
||||
.byte 0x4 ;# DW_CFA_advance_loc4
|
||||
.word L$CFI31-L$FB3
|
||||
.byte 0x83 ;# DW_CFA_offset, column 0x3
|
||||
.uleb128 0x0
|
||||
.byte 0x11 ;# DW_CFA_offset_extended_sf
|
||||
.uleb128 0x2
|
||||
.sleb128 -5
|
||||
|
||||
.byte 0x4 ;# DW_CFA_advance_loc4
|
||||
.word L$CFI32-L$CFI31
|
||||
.byte 0xd ;# DW_CFA_def_cfa_register = r3
|
||||
.uleb128 0x3
|
||||
|
||||
.align 4
|
||||
L$EFDE3:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
linux.S - (c) 2003-2004 Randolph Chung <tausq@debian.org>
|
||||
(c) 2008 Red Hat, Inc.
|
||||
(c) 2016 John David Anglin
|
||||
|
||||
HPPA Foreign Function Interface
|
||||
|
||||
|
@ -38,26 +37,24 @@
|
|||
unsigned bytes,
|
||||
unsigned flags,
|
||||
unsigned *rvalue,
|
||||
void (*fn)(void),
|
||||
ffi_go_closure *closure);
|
||||
void (*fn)(void));
|
||||
*/
|
||||
|
||||
.export ffi_call_pa32,code
|
||||
.import ffi_prep_args_pa32,code
|
||||
|
||||
.type ffi_call_pa32, @function
|
||||
.cfi_startproc
|
||||
.LFB1:
|
||||
ffi_call_pa32:
|
||||
.proc
|
||||
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
|
||||
.entry
|
||||
stw %rp, -20(%sp)
|
||||
copy %r3, %r1
|
||||
.cfi_offset 2, -20
|
||||
.cfi_register 3, 1
|
||||
.LCFI11:
|
||||
|
||||
copy %sp, %r3
|
||||
.cfi_def_cfa_register 3
|
||||
.LCFI12:
|
||||
|
||||
/* Setup the stack for calling prep_args...
|
||||
We want the stack to look like this:
|
||||
|
@ -73,8 +70,8 @@ ffi_call_pa32:
|
|||
*/
|
||||
|
||||
stwm %r1, 64(%sp)
|
||||
.cfi_offset 3, 0
|
||||
stw %r4, 12(%r3)
|
||||
.LCFI13:
|
||||
copy %sp, %r4
|
||||
|
||||
addl %arg2, %r4, %arg0 /* arg stack */
|
||||
|
@ -101,7 +98,6 @@ ffi_call_pa32:
|
|||
we need to give it a place to put the result. */
|
||||
ldw -52(%r3), %ret0 /* %ret0 <- rvalue */
|
||||
ldw -56(%r3), %r22 /* %r22 <- function to call */
|
||||
ldw -60(%r3), %ret1 /* %ret1 <- closure */
|
||||
bl $$dyncall, %r31 /* Call the user function */
|
||||
copy %r31, %rp
|
||||
|
||||
|
@ -253,27 +249,27 @@ ffi_call_pa32:
|
|||
nop
|
||||
.exit
|
||||
.procend
|
||||
.cfi_endproc
|
||||
.LFE1:
|
||||
|
||||
/* void ffi_closure_pa32(void);
|
||||
Called with ffi_closure argument in %r21. */
|
||||
Called with closure argument in %r19 */
|
||||
.export ffi_closure_pa32,code
|
||||
.import ffi_closure_inner_pa32,code
|
||||
|
||||
.type ffi_closure_pa32, @function
|
||||
.cfi_startproc
|
||||
.LFB2:
|
||||
ffi_closure_pa32:
|
||||
.proc
|
||||
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
|
||||
.entry
|
||||
|
||||
stw %rp, -20(%sp)
|
||||
.LCFI20:
|
||||
copy %r3, %r1
|
||||
.cfi_offset 2, -20
|
||||
.cfi_register 3, 1
|
||||
.LCFI21:
|
||||
copy %sp, %r3
|
||||
.cfi_def_cfa_register 3
|
||||
.LCFI22:
|
||||
stwm %r1, 64(%sp)
|
||||
.cfi_offset 3, 0
|
||||
|
||||
/* Put arguments onto the stack and call ffi_closure_inner. */
|
||||
stw %arg0, -36(%r3)
|
||||
|
@ -281,9 +277,9 @@ ffi_closure_pa32:
|
|||
stw %arg2, -44(%r3)
|
||||
stw %arg3, -48(%r3)
|
||||
|
||||
/* Closure type 0. */
|
||||
copy %r21, %arg0
|
||||
copy %r0, %arg2
|
||||
/* Retrieve closure pointer and real gp. */
|
||||
copy %r19, %arg0
|
||||
ldw 8(%r19), %r19
|
||||
bl ffi_closure_inner_pa32, %r2
|
||||
copy %r3, %arg1
|
||||
|
||||
|
@ -295,46 +291,90 @@ ffi_closure_pa32:
|
|||
|
||||
.exit
|
||||
.procend
|
||||
.cfi_endproc
|
||||
.LFE2:
|
||||
|
||||
/* void ffi_go_closure_pa32(void);
|
||||
Called with ffi_go_closure argument in %ret1. */
|
||||
.export ffi_go_closure_pa32,code
|
||||
.import ffi_closure_inner_pa32,code
|
||||
.type ffi_go_closure_pa32, @function
|
||||
.cfi_startproc
|
||||
ffi_go_closure_pa32:
|
||||
.proc
|
||||
.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
|
||||
.entry
|
||||
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
|
||||
.Lframe1:
|
||||
.word .LECIE1-.LSCIE1 ;# Length of Common Information Entry
|
||||
.LSCIE1:
|
||||
.word 0x0 ;# CIE Identifier Tag
|
||||
.byte 0x1 ;# CIE Version
|
||||
#ifdef __PIC__
|
||||
.ascii "zR\0" ;# CIE Augmentation: 'z' - data, 'R' - DW_EH_PE_... data
|
||||
#else
|
||||
.ascii "\0" ;# CIE Augmentation
|
||||
#endif
|
||||
.uleb128 0x1 ;# CIE Code Alignment Factor
|
||||
.sleb128 4 ;# CIE Data Alignment Factor
|
||||
.byte 0x2 ;# CIE RA Column
|
||||
#ifdef __PIC__
|
||||
.uleb128 0x1 ;# Augmentation size
|
||||
.byte 0x1b ;# FDE Encoding (DW_EH_PE_pcrel|DW_EH_PE_sdata4)
|
||||
#endif
|
||||
.byte 0xc ;# DW_CFA_def_cfa
|
||||
.uleb128 0x1e
|
||||
.uleb128 0x0
|
||||
.align 4
|
||||
.LECIE1:
|
||||
.LSFDE1:
|
||||
.word .LEFDE1-.LASFDE1 ;# FDE Length
|
||||
.LASFDE1:
|
||||
.word .LASFDE1-.Lframe1 ;# FDE CIE offset
|
||||
#ifdef __PIC__
|
||||
.word .LFB1-. ;# FDE initial location
|
||||
#else
|
||||
.word .LFB1 ;# FDE initial location
|
||||
#endif
|
||||
.word .LFE1-.LFB1 ;# FDE address range
|
||||
#ifdef __PIC__
|
||||
.uleb128 0x0 ;# Augmentation size: no data
|
||||
#endif
|
||||
.byte 0x4 ;# DW_CFA_advance_loc4
|
||||
.word .LCFI11-.LFB1
|
||||
.byte 0x83 ;# DW_CFA_offset, column 0x3
|
||||
.uleb128 0x0
|
||||
.byte 0x11 ;# DW_CFA_offset_extended_sf; save r2 at [r30-20]
|
||||
.uleb128 0x2
|
||||
.sleb128 -5
|
||||
|
||||
stw %rp, -20(%sp)
|
||||
copy %r3, %r1
|
||||
.cfi_offset 2, -20
|
||||
.cfi_register 3, 1
|
||||
copy %sp, %r3
|
||||
.cfi_def_cfa_register 3
|
||||
stwm %r1, 64(%sp)
|
||||
.cfi_offset 3, 0
|
||||
.byte 0x4 ;# DW_CFA_advance_loc4
|
||||
.word .LCFI12-.LCFI11
|
||||
.byte 0xd ;# DW_CFA_def_cfa_register = r3
|
||||
.uleb128 0x3
|
||||
|
||||
/* Put arguments onto the stack and call ffi_closure_inner. */
|
||||
stw %arg0, -36(%r3)
|
||||
stw %arg1, -40(%r3)
|
||||
stw %arg2, -44(%r3)
|
||||
stw %arg3, -48(%r3)
|
||||
.byte 0x4 ;# DW_CFA_advance_loc4
|
||||
.word .LCFI13-.LCFI12
|
||||
.byte 0x84 ;# DW_CFA_offset, column 0x4
|
||||
.uleb128 0x3
|
||||
|
||||
/* Closure type 1. */
|
||||
copy %ret1, %arg0
|
||||
ldi 1, %arg2
|
||||
bl ffi_closure_inner_pa32, %r2
|
||||
copy %r3, %arg1
|
||||
.align 4
|
||||
.LEFDE1:
|
||||
|
||||
ldwm -64(%sp), %r3
|
||||
ldw -20(%sp), %rp
|
||||
ldw -36(%sp), %ret0
|
||||
bv %r0(%r2)
|
||||
ldw -40(%sp), %ret1
|
||||
.LSFDE2:
|
||||
.word .LEFDE2-.LASFDE2 ;# FDE Length
|
||||
.LASFDE2:
|
||||
.word .LASFDE2-.Lframe1 ;# FDE CIE offset
|
||||
#ifdef __PIC__
|
||||
.word .LFB2-. ;# FDE initial location
|
||||
#else
|
||||
.word .LFB2 ;# FDE initial location
|
||||
#endif
|
||||
.word .LFE2-.LFB2 ;# FDE address range
|
||||
#ifdef __PIC__
|
||||
.uleb128 0x0 ;# Augmentation size: no data
|
||||
#endif
|
||||
.byte 0x4 ;# DW_CFA_advance_loc4
|
||||
.word .LCFI21-.LFB2
|
||||
.byte 0x83 ;# DW_CFA_offset, column 0x3
|
||||
.uleb128 0x0
|
||||
.byte 0x11 ;# DW_CFA_offset_extended_sf
|
||||
.uleb128 0x2
|
||||
.sleb128 -5
|
||||
|
||||
.exit
|
||||
.procend
|
||||
.cfi_endproc
|
||||
.byte 0x4 ;# DW_CFA_advance_loc4
|
||||
.word .LCFI22-.LCFI21
|
||||
.byte 0xd ;# DW_CFA_def_cfa_register = r3
|
||||
.uleb128 0x3
|
||||
|
||||
.align 4
|
||||
.LEFDE2:
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes
|
||||
past a 2^align boundary. */
|
||||
#ifdef PROF
|
||||
#define EALIGN(name, alignt, words) \
|
||||
#define EFFI_ALIGN(name, alignt, words) \
|
||||
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
|
||||
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
|
||||
.align ALIGNARG(2); \
|
||||
|
@ -104,7 +104,7 @@
|
|||
EALIGN_W_##words; \
|
||||
0:
|
||||
#else /* PROF */
|
||||
#define EALIGN(name, alignt, words) \
|
||||
#define EFFI_ALIGN(name, alignt, words) \
|
||||
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
|
||||
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
|
||||
.align ALIGNARG(alignt); \
|
||||
|
|
|
@ -353,7 +353,7 @@ Lret_type13:
|
|||
bgt Lstructend ; not a special small case
|
||||
b Lsmallstruct ; see if we need more.
|
||||
#else
|
||||
cmpi 0,r0,4
|
||||
cmpwi 0,r0,4
|
||||
bgt Lfinish ; not by value
|
||||
lg r3,0(r5)
|
||||
b Lfinish
|
||||
|
@ -494,8 +494,8 @@ LSFDE1:
|
|||
LASFDE1:
|
||||
.long LASFDE1-EH_frame1 ; FDE CIE offset
|
||||
.g_long Lstartcode-. ; FDE initial location
|
||||
.set L$set$3,LFE1-Lstartcode
|
||||
.g_long L$set$3 ; FDE address range
|
||||
.set L$set$2,LFE1-Lstartcode
|
||||
.g_long L$set$2 ; FDE address range
|
||||
.byte 0x0 ; uleb128 0x0; Augmentation size
|
||||
.byte 0x4 ; DW_CFA_advance_loc4
|
||||
.set L$set$3,LCFI1-LCFI0
|
||||
|
|
|
@ -85,8 +85,9 @@ ffi_call_int (ffi_cif *cif,
|
|||
can write r3 and r4 to memory without worrying about struct size.
|
||||
|
||||
For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
|
||||
for similar reasons. */
|
||||
unsigned long smst_buffer[8];
|
||||
for similar reasons. This bounce buffer must be aligned to 16
|
||||
bytes for use with homogeneous structs of vectors (float128). */
|
||||
float128 smst_buffer[8];
|
||||
extended_cif ecif;
|
||||
|
||||
ecif.cif = cif;
|
||||
|
@ -121,8 +122,9 @@ ffi_call_int (ffi_cif *cif,
|
|||
# endif
|
||||
/* The SYSV ABI returns a structure of up to 8 bytes in size
|
||||
left-padded in r3/r4, and the ELFv2 ABI similarly returns a
|
||||
structure of up to 8 bytes in size left-padded in r3. */
|
||||
if (rsize <= 8)
|
||||
structure of up to 8 bytes in size left-padded in r3. But
|
||||
note that a structure of a single float is not paddded. */
|
||||
if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0)
|
||||
memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -33,7 +33,10 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
extern void ffi_closure_ASM (void);
|
||||
|
||||
#if defined (FFI_GO_CLOSURES)
|
||||
extern void ffi_go_closure_ASM (void);
|
||||
#endif
|
||||
|
||||
enum {
|
||||
/* The assembly depends on these exact flags.
|
||||
|
@ -256,7 +259,7 @@ ffi_prep_args (extended_cif *ecif, unsigned long *const stack)
|
|||
case FFI_TYPE_STRUCT:
|
||||
size_al = (*ptr)->size;
|
||||
#if defined(POWERPC_DARWIN64)
|
||||
next_arg = (unsigned long *)ALIGN((char *)next_arg, (*ptr)->alignment);
|
||||
next_arg = (unsigned long *)FFI_ALIGN((char *)next_arg, (*ptr)->alignment);
|
||||
darwin64_pass_struct_by_value (*ptr, (char *) *p_argv,
|
||||
(unsigned) size_al,
|
||||
(unsigned int *) &fparg_count,
|
||||
|
@ -267,7 +270,7 @@ ffi_prep_args (extended_cif *ecif, unsigned long *const stack)
|
|||
/* If the first member of the struct is a double, then include enough
|
||||
padding in the struct size to align it to double-word. */
|
||||
if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE)
|
||||
size_al = ALIGN((*ptr)->size, 8);
|
||||
size_al = FFI_ALIGN((*ptr)->size, 8);
|
||||
|
||||
# if defined(POWERPC64)
|
||||
FFI_ASSERT (abi != FFI_DARWIN);
|
||||
|
@ -353,7 +356,7 @@ darwin64_struct_size_exceeds_gprs_p (ffi_type *s, char *src, unsigned *nfpr)
|
|||
ffi_type *p = s->elements[i];
|
||||
/* Find the start of this item (0 for the first one). */
|
||||
if (i > 0)
|
||||
struct_offset = ALIGN(struct_offset, p->alignment);
|
||||
struct_offset = FFI_ALIGN(struct_offset, p->alignment);
|
||||
|
||||
item_base = src + struct_offset;
|
||||
|
||||
|
@ -437,7 +440,7 @@ darwin64_pass_struct_floats (ffi_type *s, char *src,
|
|||
ffi_type *p = s->elements[i];
|
||||
/* Find the start of this item (0 for the first one). */
|
||||
if (i > 0)
|
||||
struct_offset = ALIGN(struct_offset, p->alignment);
|
||||
struct_offset = FFI_ALIGN(struct_offset, p->alignment);
|
||||
item_base = src + struct_offset;
|
||||
|
||||
switch (p->type)
|
||||
|
@ -528,7 +531,7 @@ darwin64_struct_floats_to_mem (ffi_type *s, char *dest, double *fprs, unsigned *
|
|||
ffi_type *p = s->elements[i];
|
||||
/* Find the start of this item (0 for the first one). */
|
||||
if (i > 0)
|
||||
struct_offset = ALIGN(struct_offset, p->alignment);
|
||||
struct_offset = FFI_ALIGN(struct_offset, p->alignment);
|
||||
item_base = dest + struct_offset;
|
||||
|
||||
switch (p->type)
|
||||
|
@ -605,10 +608,10 @@ darwin_adjust_aggregate_sizes (ffi_type *s)
|
|||
align = 4;
|
||||
#endif
|
||||
/* Pad, if necessary, before adding the current item. */
|
||||
s->size = ALIGN(s->size, align) + p->size;
|
||||
s->size = FFI_ALIGN(s->size, align) + p->size;
|
||||
}
|
||||
|
||||
s->size = ALIGN(s->size, s->alignment);
|
||||
s->size = FFI_ALIGN(s->size, s->alignment);
|
||||
|
||||
/* This should not be necessary on m64, but harmless. */
|
||||
if (s->elements[0]->type == FFI_TYPE_UINT64
|
||||
|
@ -641,10 +644,10 @@ aix_adjust_aggregate_sizes (ffi_type *s)
|
|||
align = p->alignment;
|
||||
if (i != 0 && p->type == FFI_TYPE_DOUBLE)
|
||||
align = 4;
|
||||
s->size = ALIGN(s->size, align) + p->size;
|
||||
s->size = FFI_ALIGN(s->size, align) + p->size;
|
||||
}
|
||||
|
||||
s->size = ALIGN(s->size, s->alignment);
|
||||
s->size = FFI_ALIGN(s->size, s->alignment);
|
||||
|
||||
if (s->elements[0]->type == FFI_TYPE_UINT64
|
||||
|| s->elements[0]->type == FFI_TYPE_SINT64
|
||||
|
@ -810,9 +813,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
16-byte-aligned. */
|
||||
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
|
||||
#if defined (POWERPC64)
|
||||
intarg_count = ALIGN(intarg_count, 2);
|
||||
intarg_count = FFI_ALIGN(intarg_count, 2);
|
||||
#else
|
||||
intarg_count = ALIGN(intarg_count, 4);
|
||||
intarg_count = FFI_ALIGN(intarg_count, 4);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
@ -839,7 +842,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
#if defined(POWERPC_DARWIN64)
|
||||
align_words = (*ptr)->alignment >> 3;
|
||||
if (align_words)
|
||||
intarg_count = ALIGN(intarg_count, align_words);
|
||||
intarg_count = FFI_ALIGN(intarg_count, align_words);
|
||||
/* Base size of the struct. */
|
||||
intarg_count += (size_al + 7) / 8;
|
||||
/* If 16 bytes then don't worry about floats. */
|
||||
|
@ -849,11 +852,11 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
#else
|
||||
align_words = (*ptr)->alignment >> 2;
|
||||
if (align_words)
|
||||
intarg_count = ALIGN(intarg_count, align_words);
|
||||
intarg_count = FFI_ALIGN(intarg_count, align_words);
|
||||
/* If the first member of the struct is a double, then align
|
||||
the struct to double-word.
|
||||
if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE)
|
||||
size_al = ALIGN((*ptr)->size, 8); */
|
||||
size_al = FFI_ALIGN((*ptr)->size, 8); */
|
||||
# ifdef POWERPC64
|
||||
intarg_count += (size_al + 7) / 8;
|
||||
# else
|
||||
|
@ -898,7 +901,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
bytes += NUM_GPR_ARG_REGISTERS * sizeof(long);
|
||||
|
||||
/* The stack space allocated needs to be a multiple of 16 bytes. */
|
||||
bytes = ALIGN(bytes, 16) ;
|
||||
bytes = FFI_ALIGN(bytes, 16) ;
|
||||
|
||||
cif->flags = flags;
|
||||
cif->bytes = bytes;
|
||||
|
@ -909,8 +912,10 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
extern void ffi_call_AIX(extended_cif *, long, unsigned, unsigned *,
|
||||
void (*fn)(void), void (*fn2)(void));
|
||||
|
||||
#if defined (FFI_GO_CLOSURES)
|
||||
extern void ffi_call_go_AIX(extended_cif *, long, unsigned, unsigned *,
|
||||
void (*fn)(void), void (*fn2)(void), void *closure);
|
||||
#endif
|
||||
|
||||
extern void ffi_call_DARWIN(extended_cif *, long, unsigned, unsigned *,
|
||||
void (*fn)(void), void (*fn2)(void), ffi_type*);
|
||||
|
@ -950,6 +955,7 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined (FFI_GO_CLOSURES)
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
|
||||
void *closure)
|
||||
|
@ -981,6 +987,7 @@ ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void flush_icache(char *);
|
||||
static void flush_range(char *, int);
|
||||
|
@ -1110,6 +1117,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
#if defined (FFI_GO_CLOSURES)
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure* closure,
|
||||
ffi_cif* cif,
|
||||
|
@ -1133,6 +1141,7 @@ ffi_prep_go_closure (ffi_go_closure* closure,
|
|||
}
|
||||
return FFI_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
flush_icache(char *addr)
|
||||
|
@ -1168,9 +1177,11 @@ ffi_type *
|
|||
ffi_closure_helper_DARWIN (ffi_closure *, void *,
|
||||
unsigned long *, ffi_dblfl *);
|
||||
|
||||
#if defined (FFI_GO_CLOSURES)
|
||||
ffi_type *
|
||||
ffi_go_closure_helper_DARWIN (ffi_go_closure*, void *,
|
||||
unsigned long *, ffi_dblfl *);
|
||||
#endif
|
||||
|
||||
/* Basically the trampoline invokes ffi_closure_ASM, and on
|
||||
entry, r11 holds the address of the closure.
|
||||
|
@ -1272,7 +1283,7 @@ ffi_closure_helper_common (ffi_cif* cif,
|
|||
case FFI_TYPE_STRUCT:
|
||||
size_al = arg_types[i]->size;
|
||||
#if defined(POWERPC_DARWIN64)
|
||||
pgr = (unsigned long *)ALIGN((char *)pgr, arg_types[i]->alignment);
|
||||
pgr = (unsigned long *)FFI_ALIGN((char *)pgr, arg_types[i]->alignment);
|
||||
if (size_al < 3 || size_al == 4)
|
||||
{
|
||||
avalue[i] = ((char *)pgr)+8-size_al;
|
||||
|
@ -1297,7 +1308,7 @@ ffi_closure_helper_common (ffi_cif* cif,
|
|||
/* If the first member of the struct is a double, then align
|
||||
the struct to double-word. */
|
||||
if (arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE)
|
||||
size_al = ALIGN(arg_types[i]->size, 8);
|
||||
size_al = FFI_ALIGN(arg_types[i]->size, 8);
|
||||
# if defined(POWERPC64)
|
||||
FFI_ASSERT (cif->abi != FFI_DARWIN);
|
||||
avalue[i] = pgr;
|
||||
|
@ -1430,6 +1441,7 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
|
|||
closure->user_data, rvalue, pgr, pfr);
|
||||
}
|
||||
|
||||
#if defined (FFI_GO_CLOSURES)
|
||||
ffi_type *
|
||||
ffi_go_closure_helper_DARWIN (ffi_go_closure *closure, void *rvalue,
|
||||
unsigned long *pgr, ffi_dblfl *pfr)
|
||||
|
@ -1437,4 +1449,4 @@ ffi_go_closure_helper_DARWIN (ffi_go_closure *closure, void *rvalue,
|
|||
return ffi_closure_helper_common (closure->cif, closure->fun,
|
||||
closure, rvalue, pgr, pfr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,8 @@
|
|||
/* About the LINUX64 ABI. */
|
||||
enum {
|
||||
NUM_GPR_ARG_REGISTERS64 = 8,
|
||||
NUM_FPR_ARG_REGISTERS64 = 13
|
||||
NUM_FPR_ARG_REGISTERS64 = 13,
|
||||
NUM_VEC_ARG_REGISTERS64 = 12,
|
||||
};
|
||||
enum { ASM_NEEDS_REGISTERS64 = 4 };
|
||||
|
||||
|
@ -63,10 +64,31 @@ ffi_prep_types_linux64 (ffi_abi abi)
|
|||
|
||||
|
||||
static unsigned int
|
||||
discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
|
||||
discover_homogeneous_aggregate (ffi_abi abi,
|
||||
const ffi_type *t,
|
||||
unsigned int *elnum)
|
||||
{
|
||||
switch (t->type)
|
||||
{
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
/* 64-bit long doubles are equivalent to doubles. */
|
||||
if ((abi & FFI_LINUX_LONG_DOUBLE_128) == 0)
|
||||
{
|
||||
*elnum = 1;
|
||||
return FFI_TYPE_DOUBLE;
|
||||
}
|
||||
/* IBM extended precision values use unaligned pairs
|
||||
of FPRs, but according to the ABI must be considered
|
||||
distinct from doubles. They are also limited to a
|
||||
maximum of four members in a homogeneous aggregate. */
|
||||
else if ((abi & FFI_LINUX_LONG_DOUBLE_IEEE128) == 0)
|
||||
{
|
||||
*elnum = 2;
|
||||
return FFI_TYPE_LONGDOUBLE;
|
||||
}
|
||||
/* Fall through. */
|
||||
#endif
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
*elnum = 1;
|
||||
|
@ -79,7 +101,7 @@ discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
|
|||
while (*el)
|
||||
{
|
||||
unsigned int el_elt, el_elnum = 0;
|
||||
el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
|
||||
el_elt = discover_homogeneous_aggregate (abi, *el, &el_elnum);
|
||||
if (el_elt == 0
|
||||
|| (base_elt && base_elt != el_elt))
|
||||
return 0;
|
||||
|
@ -110,13 +132,23 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||
{
|
||||
ffi_type **ptr;
|
||||
unsigned bytes;
|
||||
unsigned i, fparg_count = 0, intarg_count = 0;
|
||||
unsigned i, fparg_count = 0, intarg_count = 0, vecarg_count = 0;
|
||||
unsigned flags = cif->flags;
|
||||
unsigned int elt, elnum;
|
||||
unsigned elt, elnum, rtype;
|
||||
|
||||
#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
|
||||
/* If compiled without long double support.. */
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
|
||||
/* If compiled without long double support... */
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0 ||
|
||||
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
return FFI_BAD_ABI;
|
||||
#elif !defined(__VEC__)
|
||||
/* If compiled without vector register support (used by assembly)... */
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
return FFI_BAD_ABI;
|
||||
#else
|
||||
/* If the IEEE128 flag is set, but long double is only 64 bits wide... */
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) == 0 &&
|
||||
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
return FFI_BAD_ABI;
|
||||
#endif
|
||||
|
||||
|
@ -138,10 +170,19 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||
#endif
|
||||
|
||||
/* Return value handling. */
|
||||
switch (cif->rtype->type)
|
||||
rtype = cif->rtype->type;
|
||||
#if _CALL_ELF == 2
|
||||
homogeneous:
|
||||
#endif
|
||||
switch (rtype)
|
||||
{
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
flags |= FLAG_RETURNS_VEC;
|
||||
break;
|
||||
}
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
|
||||
flags |= FLAG_RETURNS_128BITS;
|
||||
/* Fall through. */
|
||||
|
@ -164,19 +205,18 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||
|
||||
case FFI_TYPE_STRUCT:
|
||||
#if _CALL_ELF == 2
|
||||
elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
|
||||
elt = discover_homogeneous_aggregate (cif->abi, cif->rtype, &elnum);
|
||||
if (elt)
|
||||
{
|
||||
if (elt == FFI_TYPE_DOUBLE)
|
||||
flags |= FLAG_RETURNS_64BITS;
|
||||
flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
|
||||
break;
|
||||
}
|
||||
{
|
||||
flags |= FLAG_RETURNS_SMST;
|
||||
rtype = elt;
|
||||
goto homogeneous;
|
||||
}
|
||||
if (cif->rtype->size <= 16)
|
||||
{
|
||||
flags |= FLAG_RETURNS_SMST;
|
||||
break;
|
||||
}
|
||||
{
|
||||
flags |= FLAG_RETURNS_SMST;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
intarg_count++;
|
||||
flags |= FLAG_RETVAL_REFERENCE;
|
||||
|
@ -198,6 +238,15 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||
{
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
vecarg_count++;
|
||||
/* Align to 16 bytes, plus the 16-byte argument. */
|
||||
intarg_count = (intarg_count + 3) & ~0x1;
|
||||
if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
|
||||
flags |= FLAG_ARG_NEEDS_PSAVE;
|
||||
break;
|
||||
}
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
|
||||
{
|
||||
fparg_count++;
|
||||
|
@ -221,10 +270,21 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||
align = 16;
|
||||
align = align / 8;
|
||||
if (align > 1)
|
||||
intarg_count = ALIGN (intarg_count, align);
|
||||
intarg_count = FFI_ALIGN (intarg_count, align);
|
||||
}
|
||||
intarg_count += ((*ptr)->size + 7) / 8;
|
||||
elt = discover_homogeneous_aggregate (*ptr, &elnum);
|
||||
elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum);
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
if (elt == FFI_TYPE_LONGDOUBLE &&
|
||||
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
vecarg_count += elnum;
|
||||
if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
|
||||
flags |= FLAG_ARG_NEEDS_PSAVE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (elt)
|
||||
{
|
||||
fparg_count += elnum;
|
||||
|
@ -263,10 +323,17 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
|
|||
flags |= FLAG_FP_ARGUMENTS;
|
||||
if (intarg_count > 4)
|
||||
flags |= FLAG_4_GPR_ARGUMENTS;
|
||||
if (vecarg_count != 0)
|
||||
flags |= FLAG_VEC_ARGUMENTS;
|
||||
|
||||
/* Space for the FPR registers, if needed. */
|
||||
if (fparg_count != 0)
|
||||
bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
|
||||
/* Space for the vector registers, if needed, aligned to 16 bytes. */
|
||||
if (vecarg_count != 0) {
|
||||
bytes = (bytes + 15) & ~0xF;
|
||||
bytes += NUM_VEC_ARG_REGISTERS64 * sizeof (float128);
|
||||
}
|
||||
|
||||
/* Stack space. */
|
||||
#if _CALL_ELF == 2
|
||||
|
@ -349,6 +416,8 @@ ffi_prep_cif_linux64_var (ffi_cif *cif,
|
|||
|--------------------------------------------| |
|
||||
| FPR registers f1-f13 (optional) 13*8 | |
|
||||
|--------------------------------------------| |
|
||||
| VEC registers v2-v13 (optional) 12*16 | |
|
||||
|--------------------------------------------| |
|
||||
| Parameter save area | |
|
||||
|--------------------------------------------| |
|
||||
| TOC save area 8 | |
|
||||
|
@ -378,6 +447,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
unsigned long *ul;
|
||||
float *f;
|
||||
double *d;
|
||||
float128 *f128;
|
||||
size_t p;
|
||||
} valp;
|
||||
|
||||
|
@ -391,11 +461,16 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
valp rest;
|
||||
valp next_arg;
|
||||
|
||||
/* 'fpr_base' points at the space for fpr3, and grows upwards as
|
||||
/* 'fpr_base' points at the space for f1, and grows upwards as
|
||||
we use FPR registers. */
|
||||
valp fpr_base;
|
||||
unsigned int fparg_count;
|
||||
|
||||
/* 'vec_base' points at the space for v2, and grows upwards as
|
||||
we use vector registers. */
|
||||
valp vec_base;
|
||||
unsigned int vecarg_count;
|
||||
|
||||
unsigned int i, words, nargs, nfixedargs;
|
||||
ffi_type **ptr;
|
||||
double double_tmp;
|
||||
|
@ -412,6 +487,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
unsigned long **ul;
|
||||
float **f;
|
||||
double **d;
|
||||
float128 **f128;
|
||||
} p_argv;
|
||||
unsigned long gprvalue;
|
||||
unsigned long align;
|
||||
|
@ -426,11 +502,21 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
#endif
|
||||
fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
|
||||
fparg_count = 0;
|
||||
/* Place the vector args below the FPRs, if used, else the GPRs. */
|
||||
if (ecif->cif->flags & FLAG_FP_ARGUMENTS)
|
||||
vec_base.p = fpr_base.p & ~0xF;
|
||||
else
|
||||
vec_base.p = gpr_base.p;
|
||||
vec_base.f128 -= NUM_VEC_ARG_REGISTERS64;
|
||||
vecarg_count = 0;
|
||||
next_arg.ul = gpr_base.ul;
|
||||
|
||||
/* Check that everything starts aligned properly. */
|
||||
FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
|
||||
FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
|
||||
FFI_ASSERT (((unsigned long) gpr_base.c & 0xF) == 0);
|
||||
FFI_ASSERT (((unsigned long) gpr_end.c & 0xF) == 0);
|
||||
FFI_ASSERT (((unsigned long) vec_base.c & 0xF) == 0);
|
||||
FFI_ASSERT ((bytes & 0xF) == 0);
|
||||
|
||||
/* Deal with return values that are actually pass-by-reference. */
|
||||
|
@ -455,6 +541,22 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
{
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
next_arg.p = FFI_ALIGN (next_arg.p, 16);
|
||||
if (next_arg.ul == gpr_end.ul)
|
||||
next_arg.ul = rest.ul;
|
||||
if (vecarg_count < NUM_VEC_ARG_REGISTERS64 && i < nfixedargs)
|
||||
memcpy (vec_base.f128++, *p_argv.f128, sizeof (float128));
|
||||
else
|
||||
memcpy (next_arg.f128, *p_argv.f128, sizeof (float128));
|
||||
if (++next_arg.f128 == gpr_end.f128)
|
||||
next_arg.f128 = rest.f128;
|
||||
vecarg_count++;
|
||||
FFI_ASSERT (__LDBL_MANT_DIG__ == 113);
|
||||
FFI_ASSERT (flags & FLAG_VEC_ARGUMENTS);
|
||||
break;
|
||||
}
|
||||
if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
|
||||
{
|
||||
double_tmp = (*p_argv.d)[0];
|
||||
|
@ -492,7 +594,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
/* Fall through. */
|
||||
#endif
|
||||
case FFI_TYPE_DOUBLE:
|
||||
#if _CALL_ELF != 2
|
||||
do_double:
|
||||
#endif
|
||||
double_tmp = **p_argv.d;
|
||||
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
|
||||
{
|
||||
|
@ -511,7 +615,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
#if _CALL_ELF != 2
|
||||
do_float:
|
||||
#endif
|
||||
double_tmp = **p_argv.f;
|
||||
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
|
||||
{
|
||||
|
@ -548,9 +654,13 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
if (align > 16)
|
||||
align = 16;
|
||||
if (align > 1)
|
||||
next_arg.p = ALIGN (next_arg.p, align);
|
||||
{
|
||||
next_arg.p = FFI_ALIGN (next_arg.p, align);
|
||||
if (next_arg.ul == gpr_end.ul)
|
||||
next_arg.ul = rest.ul;
|
||||
}
|
||||
}
|
||||
elt = discover_homogeneous_aggregate (*ptr, &elnum);
|
||||
elt = discover_homogeneous_aggregate (ecif->cif->abi, *ptr, &elnum);
|
||||
if (elt)
|
||||
{
|
||||
#if _CALL_ELF == 2
|
||||
|
@ -558,9 +668,29 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
void *v;
|
||||
float *f;
|
||||
double *d;
|
||||
float128 *f128;
|
||||
} arg;
|
||||
|
||||
arg.v = *p_argv.v;
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
if (elt == FFI_TYPE_LONGDOUBLE &&
|
||||
(ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (vecarg_count < NUM_VEC_ARG_REGISTERS64
|
||||
&& i < nfixedargs)
|
||||
memcpy (vec_base.f128++, arg.f128, sizeof (float128));
|
||||
else
|
||||
memcpy (next_arg.f128, arg.f128++, sizeof (float128));
|
||||
if (++next_arg.f128 == gpr_end.f128)
|
||||
next_arg.f128 = rest.f128;
|
||||
vecarg_count++;
|
||||
}
|
||||
while (--elnum != 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (elt == FFI_TYPE_FLOAT)
|
||||
{
|
||||
do
|
||||
|
@ -576,11 +706,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
|
|||
fparg_count++;
|
||||
}
|
||||
while (--elnum != 0);
|
||||
if ((next_arg.p & 3) != 0)
|
||||
{
|
||||
if (++next_arg.f == gpr_end.f)
|
||||
next_arg.f = rest.f;
|
||||
}
|
||||
if ((next_arg.p & 7) != 0)
|
||||
if (++next_arg.f == gpr_end.f)
|
||||
next_arg.f = rest.f;
|
||||
}
|
||||
else
|
||||
do
|
||||
|
@ -733,17 +861,20 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
void *user_data,
|
||||
void *rvalue,
|
||||
unsigned long *pst,
|
||||
ffi_dblfl *pfr)
|
||||
ffi_dblfl *pfr,
|
||||
float128 *pvec)
|
||||
{
|
||||
/* rvalue is the pointer to space for return value in closure assembly */
|
||||
/* pst is the pointer to parameter save area
|
||||
(r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
|
||||
/* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
|
||||
/* pvec is the pointer to where v2-v13 are stored in ffi_closure_LINUX64 */
|
||||
|
||||
void **avalue;
|
||||
ffi_type **arg_types;
|
||||
unsigned long i, avn, nfixedargs;
|
||||
ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
|
||||
float128 *end_pvec = pvec + NUM_VEC_ARG_REGISTERS64;
|
||||
unsigned long align;
|
||||
|
||||
avalue = alloca (cif->nargs * sizeof (void *));
|
||||
|
@ -811,9 +942,9 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
if (align > 16)
|
||||
align = 16;
|
||||
if (align > 1)
|
||||
pst = (unsigned long *) ALIGN ((size_t) pst, align);
|
||||
pst = (unsigned long *) FFI_ALIGN ((size_t) pst, align);
|
||||
}
|
||||
elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
|
||||
elt = discover_homogeneous_aggregate (cif->abi, arg_types[i], &elnum);
|
||||
if (elt)
|
||||
{
|
||||
#if _CALL_ELF == 2
|
||||
|
@ -822,6 +953,7 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
unsigned long *ul;
|
||||
float *f;
|
||||
double *d;
|
||||
float128 *f128;
|
||||
size_t p;
|
||||
} to, from;
|
||||
|
||||
|
@ -829,6 +961,17 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
aggregate size is not greater than the space taken by
|
||||
the registers so store back to the register/parameter
|
||||
save arrays. */
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
if (elt == FFI_TYPE_LONGDOUBLE &&
|
||||
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
if (pvec + elnum <= end_pvec)
|
||||
to.v = pvec;
|
||||
else
|
||||
to.v = pst;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (pfr + elnum <= end_pfr)
|
||||
to.v = pfr;
|
||||
else
|
||||
|
@ -836,6 +979,23 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
|
||||
avalue[i] = to.v;
|
||||
from.ul = pst;
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
if (elt == FFI_TYPE_LONGDOUBLE &&
|
||||
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (pvec < end_pvec && i < nfixedargs)
|
||||
memcpy (to.f128, pvec++, sizeof (float128));
|
||||
else
|
||||
memcpy (to.f128, from.f128, sizeof (float128));
|
||||
to.f128++;
|
||||
from.f128++;
|
||||
}
|
||||
while (--elnum != 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (elt == FFI_TYPE_FLOAT)
|
||||
{
|
||||
do
|
||||
|
@ -891,7 +1051,18 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
|
||||
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
|
||||
{
|
||||
if (((unsigned long) pst & 0xF) != 0)
|
||||
++pst;
|
||||
if (pvec < end_pvec && i < nfixedargs)
|
||||
avalue[i] = pvec++;
|
||||
else
|
||||
avalue[i] = pst;
|
||||
pst += 2;
|
||||
break;
|
||||
}
|
||||
else if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
|
||||
{
|
||||
if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
|
||||
{
|
||||
|
@ -915,7 +1086,9 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
/* Fall through. */
|
||||
#endif
|
||||
case FFI_TYPE_DOUBLE:
|
||||
#if _CALL_ELF != 2
|
||||
do_double:
|
||||
#endif
|
||||
/* On the outgoing stack all values are aligned to 8 */
|
||||
/* there are 13 64bit floating point registers */
|
||||
|
||||
|
@ -930,7 +1103,9 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
break;
|
||||
|
||||
case FFI_TYPE_FLOAT:
|
||||
#if _CALL_ELF != 2
|
||||
do_float:
|
||||
#endif
|
||||
if (pfr < end_pfr && i < nfixedargs)
|
||||
{
|
||||
/* Float values are stored as doubles in the
|
||||
|
@ -962,13 +1137,17 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
|
|||
/* Tell ffi_closure_LINUX64 how to perform return type promotions. */
|
||||
if ((cif->flags & FLAG_RETURNS_SMST) != 0)
|
||||
{
|
||||
if ((cif->flags & FLAG_RETURNS_FP) == 0)
|
||||
if ((cif->flags & (FLAG_RETURNS_FP | FLAG_RETURNS_VEC)) == 0)
|
||||
return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
|
||||
else if ((cif->flags & FLAG_RETURNS_VEC) != 0)
|
||||
return FFI_V2_TYPE_VECTOR_HOMOG;
|
||||
else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
|
||||
return FFI_V2_TYPE_DOUBLE_HOMOG;
|
||||
else
|
||||
return FFI_V2_TYPE_FLOAT_HOMOG;
|
||||
}
|
||||
if ((cif->flags & FLAG_RETURNS_VEC) != 0)
|
||||
return FFI_V2_TYPE_VECTOR;
|
||||
return cif->rtype->type;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -31,22 +31,24 @@
|
|||
enum {
|
||||
/* The assembly depends on these exact flags. */
|
||||
/* These go in cr7 */
|
||||
FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
|
||||
FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
|
||||
FLAG_RETURNS_NOTHING = 1 << (31-30),
|
||||
FLAG_RETURNS_FP = 1 << (31-29),
|
||||
FLAG_RETURNS_64BITS = 1 << (31-28),
|
||||
FLAG_RETURNS_VEC = 1 << (31-28),
|
||||
|
||||
/* This goes in cr6 */
|
||||
FLAG_RETURNS_128BITS = 1 << (31-27),
|
||||
/* These go in cr6 */
|
||||
FLAG_RETURNS_64BITS = 1 << (31-27),
|
||||
FLAG_RETURNS_128BITS = 1 << (31-26),
|
||||
|
||||
FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */
|
||||
FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */
|
||||
|
||||
/* These go in cr1 */
|
||||
FLAG_ARG_NEEDS_COPY = 1 << (31- 7), /* Used by sysv code */
|
||||
FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by linux64 code */
|
||||
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
|
||||
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
|
||||
FLAG_RETVAL_REFERENCE = 1 << (31- 4)
|
||||
FLAG_RETVAL_REFERENCE = 1 << (31- 4),
|
||||
FLAG_VEC_ARGUMENTS = 1 << (31- 3),
|
||||
};
|
||||
|
||||
typedef union
|
||||
|
@ -55,6 +57,14 @@ typedef union
|
|||
double d;
|
||||
} ffi_dblfl;
|
||||
|
||||
#if defined(__FLOAT128_TYPE__) && defined(__HAVE_FLOAT128)
|
||||
typedef _Float128 float128;
|
||||
#elif defined(__FLOAT128__)
|
||||
typedef __float128 float128;
|
||||
#else
|
||||
typedef char float128[16] __attribute__((aligned(16)));
|
||||
#endif
|
||||
|
||||
void FFI_HIDDEN ffi_closure_SYSV (void);
|
||||
void FFI_HIDDEN ffi_go_closure_sysv (void);
|
||||
void FFI_HIDDEN ffi_call_SYSV(extended_cif *, void (*)(void), void *,
|
||||
|
@ -91,4 +101,5 @@ int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_cif *,
|
|||
void (*) (ffi_cif *, void *,
|
||||
void **, void *),
|
||||
void *, void *,
|
||||
unsigned long *, ffi_dblfl *);
|
||||
unsigned long *, ffi_dblfl *,
|
||||
float128 *);
|
||||
|
|
|
@ -91,15 +91,19 @@ typedef enum ffi_abi {
|
|||
/* This and following bits can reuse FFI_COMPAT values. */
|
||||
FFI_LINUX_STRUCT_ALIGN = 1,
|
||||
FFI_LINUX_LONG_DOUBLE_128 = 2,
|
||||
FFI_LINUX_LONG_DOUBLE_IEEE128 = 4,
|
||||
FFI_DEFAULT_ABI = (FFI_LINUX
|
||||
# ifdef __STRUCT_PARM_ALIGN__
|
||||
| FFI_LINUX_STRUCT_ALIGN
|
||||
# endif
|
||||
# ifdef __LONG_DOUBLE_128__
|
||||
| FFI_LINUX_LONG_DOUBLE_128
|
||||
# ifdef __LONG_DOUBLE_IEEE128__
|
||||
| FFI_LINUX_LONG_DOUBLE_IEEE128
|
||||
# endif
|
||||
# endif
|
||||
),
|
||||
FFI_LAST_ABI = 12
|
||||
FFI_LAST_ABI = 16
|
||||
|
||||
# else
|
||||
/* This bit, always set in new code, must not be set in any of the
|
||||
|
@ -167,9 +171,11 @@ typedef enum ffi_abi {
|
|||
#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2)
|
||||
|
||||
/* Used by ELFv2 for homogenous structure returns. */
|
||||
#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 1)
|
||||
#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 2)
|
||||
#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 3)
|
||||
#define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1)
|
||||
#define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2)
|
||||
#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3)
|
||||
#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4)
|
||||
#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5)
|
||||
|
||||
#if _CALL_ELF == 2
|
||||
# define FFI_TRAMPOLINE_SIZE 32
|
||||
|
|
|
@ -109,40 +109,70 @@ ffi_call_LINUX64:
|
|||
ld %r2, 8(%r29)
|
||||
# endif
|
||||
/* Now do the call. */
|
||||
/* Set up cr1 with bits 4-7 of the flags. */
|
||||
mtcrf 0x40, %r31
|
||||
/* Set up cr1 with bits 3-7 of the flags. */
|
||||
mtcrf 0xc0, %r31
|
||||
|
||||
/* Get the address to call into CTR. */
|
||||
mtctr %r12
|
||||
/* Load all those argument registers. */
|
||||
ld %r3, -32-(8*8)(%r28)
|
||||
ld %r4, -32-(7*8)(%r28)
|
||||
ld %r5, -32-(6*8)(%r28)
|
||||
ld %r6, -32-(5*8)(%r28)
|
||||
addi %r29, %r28, -32-(8*8)
|
||||
ld %r3, (0*8)(%r29)
|
||||
ld %r4, (1*8)(%r29)
|
||||
ld %r5, (2*8)(%r29)
|
||||
ld %r6, (3*8)(%r29)
|
||||
bf- 5, 1f
|
||||
ld %r7, -32-(4*8)(%r28)
|
||||
ld %r8, -32-(3*8)(%r28)
|
||||
ld %r9, -32-(2*8)(%r28)
|
||||
ld %r10, -32-(1*8)(%r28)
|
||||
ld %r7, (4*8)(%r29)
|
||||
ld %r8, (5*8)(%r29)
|
||||
ld %r9, (6*8)(%r29)
|
||||
ld %r10, (7*8)(%r29)
|
||||
1:
|
||||
|
||||
/* Load all the FP registers. */
|
||||
bf- 6, 2f
|
||||
lfd %f1, -32-(21*8)(%r28)
|
||||
lfd %f2, -32-(20*8)(%r28)
|
||||
lfd %f3, -32-(19*8)(%r28)
|
||||
lfd %f4, -32-(18*8)(%r28)
|
||||
lfd %f5, -32-(17*8)(%r28)
|
||||
lfd %f6, -32-(16*8)(%r28)
|
||||
lfd %f7, -32-(15*8)(%r28)
|
||||
lfd %f8, -32-(14*8)(%r28)
|
||||
lfd %f9, -32-(13*8)(%r28)
|
||||
lfd %f10, -32-(12*8)(%r28)
|
||||
lfd %f11, -32-(11*8)(%r28)
|
||||
lfd %f12, -32-(10*8)(%r28)
|
||||
lfd %f13, -32-(9*8)(%r28)
|
||||
addi %r29, %r29, -(14*8)
|
||||
lfd %f1, ( 1*8)(%r29)
|
||||
lfd %f2, ( 2*8)(%r29)
|
||||
lfd %f3, ( 3*8)(%r29)
|
||||
lfd %f4, ( 4*8)(%r29)
|
||||
lfd %f5, ( 5*8)(%r29)
|
||||
lfd %f6, ( 6*8)(%r29)
|
||||
lfd %f7, ( 7*8)(%r29)
|
||||
lfd %f8, ( 8*8)(%r29)
|
||||
lfd %f9, ( 9*8)(%r29)
|
||||
lfd %f10, (10*8)(%r29)
|
||||
lfd %f11, (11*8)(%r29)
|
||||
lfd %f12, (12*8)(%r29)
|
||||
lfd %f13, (13*8)(%r29)
|
||||
2:
|
||||
|
||||
/* Load all the vector registers. */
|
||||
bf- 3, 3f
|
||||
addi %r29, %r29, -16
|
||||
lvx %v13, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v12, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v11, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v10, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v9, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v8, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v7, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v6, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v5, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v4, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v3, 0, %r29
|
||||
addi %r29, %r29, -16
|
||||
lvx %v2, 0, %r29
|
||||
3:
|
||||
|
||||
/* Make the call. */
|
||||
ld %r11, 8(%r28)
|
||||
bctrl
|
||||
|
@ -160,6 +190,7 @@ ffi_call_LINUX64:
|
|||
bt 31, .Lstruct_return_value
|
||||
bt 30, .Ldone_return_value
|
||||
bt 29, .Lfp_return_value
|
||||
bt 28, .Lvec_return_value
|
||||
std %r3, 0(%r30)
|
||||
/* Fall through... */
|
||||
|
||||
|
@ -175,12 +206,16 @@ ffi_call_LINUX64:
|
|||
ld %r31, -8(%r1)
|
||||
blr
|
||||
|
||||
.Lvec_return_value:
|
||||
stvx %v2, 0, %r30
|
||||
b .Ldone_return_value
|
||||
|
||||
.Lfp_return_value:
|
||||
.cfi_def_cfa_register 28
|
||||
bf 28, .Lfloat_return_value
|
||||
stfd %f1, 0(%r30)
|
||||
mtcrf 0x02, %r31 /* cr6 */
|
||||
bf 27, .Ldone_return_value
|
||||
bf 27, .Lfloat_return_value
|
||||
stfd %f1, 0(%r30)
|
||||
bf 26, .Ldone_return_value
|
||||
stfd %f2, 8(%r30)
|
||||
b .Ldone_return_value
|
||||
.Lfloat_return_value:
|
||||
|
@ -188,8 +223,9 @@ ffi_call_LINUX64:
|
|||
b .Ldone_return_value
|
||||
|
||||
.Lstruct_return_value:
|
||||
bf 29, .Lsmall_struct
|
||||
bf 28, .Lfloat_homog_return_value
|
||||
bf 29, .Lvec_homog_or_small_struct
|
||||
mtcrf 0x02, %r31 /* cr6 */
|
||||
bf 27, .Lfloat_homog_return_value
|
||||
stfd %f1, 0(%r30)
|
||||
stfd %f2, 8(%r30)
|
||||
stfd %f3, 16(%r30)
|
||||
|
@ -211,6 +247,25 @@ ffi_call_LINUX64:
|
|||
stfs %f8, 28(%r30)
|
||||
b .Ldone_return_value
|
||||
|
||||
.Lvec_homog_or_small_struct:
|
||||
bf 28, .Lsmall_struct
|
||||
stvx %v2, 0, %r30
|
||||
addi %r30, %r30, 16
|
||||
stvx %v3, 0, %r30
|
||||
addi %r30, %r30, 16
|
||||
stvx %v4, 0, %r30
|
||||
addi %r30, %r30, 16
|
||||
stvx %v5, 0, %r30
|
||||
addi %r30, %r30, 16
|
||||
stvx %v6, 0, %r30
|
||||
addi %r30, %r30, 16
|
||||
stvx %v7, 0, %r30
|
||||
addi %r30, %r30, 16
|
||||
stvx %v8, 0, %r30
|
||||
addi %r30, %r30, 16
|
||||
stvx %v9, 0, %r30
|
||||
b .Ldone_return_value
|
||||
|
||||
.Lsmall_struct:
|
||||
std %r3, 0(%r30)
|
||||
std %r4, 8(%r30)
|
||||
|
|
|
@ -63,9 +63,15 @@ ffi_closure_LINUX64:
|
|||
# endif
|
||||
|
||||
# if _CALL_ELF == 2
|
||||
# 32 byte special reg save area + 64 byte parm save area
|
||||
# + 64 byte retval area + 13*8 fpr save area + round to 16
|
||||
# define STACKFRAME 272
|
||||
# ifdef __VEC__
|
||||
# 32 byte special reg save area + 64 byte parm save area
|
||||
# + 128 byte retval area + 13*8 fpr save area + 12*16 vec save area + round to 16
|
||||
# define STACKFRAME 528
|
||||
# else
|
||||
# 32 byte special reg save area + 64 byte parm save area
|
||||
# + 64 byte retval area + 13*8 fpr save area + round to 16
|
||||
# define STACKFRAME 272
|
||||
# endif
|
||||
# define PARMSAVE 32
|
||||
# define RETVAL PARMSAVE+64
|
||||
# else
|
||||
|
@ -148,6 +154,35 @@ ffi_closure_LINUX64:
|
|||
# load up the pointer to the saved fpr registers
|
||||
addi %r8, %r1, -104
|
||||
|
||||
# ifdef __VEC__
|
||||
# load up the pointer to the saved vector registers
|
||||
# 8 bytes padding for 16-byte alignment at -112(%r1)
|
||||
addi %r9, %r8, -24
|
||||
stvx %v13, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v12, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v11, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v10, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v9, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v8, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v7, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v6, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v5, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v4, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v3, 0, %r9
|
||||
addi %r9, %r9, -16
|
||||
stvx %v2, 0, %r9
|
||||
# endif
|
||||
|
||||
# load up the pointer to the result storage
|
||||
addi %r6, %r1, -STACKFRAME+RETVAL
|
||||
|
||||
|
@ -323,6 +358,16 @@ ffi_closure_LINUX64:
|
|||
.cfi_def_cfa_offset 0
|
||||
blr
|
||||
.cfi_def_cfa_offset STACKFRAME
|
||||
# case FFI_V2_TYPE_VECTOR
|
||||
addi %r3, %r1, RETVAL
|
||||
lvx %v2, 0, %r3
|
||||
mtlr %r0
|
||||
b .Lfinish
|
||||
# case FFI_V2_TYPE_VECTOR_HOMOG
|
||||
addi %r3, %r1, RETVAL
|
||||
lvx %v2, 0, %r3
|
||||
addi %r3, %r3, 16
|
||||
b .Lmorevector
|
||||
# case FFI_V2_TYPE_FLOAT_HOMOG
|
||||
lfs %f1, RETVAL+0(%r1)
|
||||
lfs %f2, RETVAL+4(%r1)
|
||||
|
@ -342,6 +387,25 @@ ffi_closure_LINUX64:
|
|||
.cfi_def_cfa_offset 0
|
||||
blr
|
||||
.cfi_def_cfa_offset STACKFRAME
|
||||
.Lmorevector:
|
||||
lvx %v3, 0, %r3
|
||||
addi %r3, %r3, 16
|
||||
lvx %v4, 0, %r3
|
||||
addi %r3, %r3, 16
|
||||
lvx %v5, 0, %r3
|
||||
mtlr %r0
|
||||
addi %r3, %r3, 16
|
||||
lvx %v6, 0, %r3
|
||||
addi %r3, %r3, 16
|
||||
lvx %v7, 0, %r3
|
||||
addi %r3, %r3, 16
|
||||
lvx %v8, 0, %r3
|
||||
addi %r3, %r3, 16
|
||||
lvx %v9, 0, %r3
|
||||
addi %r1, %r1, STACKFRAME
|
||||
.cfi_def_cfa_offset 0
|
||||
blr
|
||||
.cfi_def_cfa_offset STACKFRAME
|
||||
.Lmorefloat:
|
||||
lfs %f4, RETVAL+12(%r1)
|
||||
mtlr %r0
|
||||
|
|
|
@ -104,17 +104,16 @@ ENTRY(ffi_call_SYSV)
|
|||
bctrl
|
||||
|
||||
/* Now, deal with the return value. */
|
||||
mtcrf 0x01,%r31 /* cr7 */
|
||||
mtcrf 0x03,%r31 /* cr6-cr7 */
|
||||
bt- 31,L(small_struct_return_value)
|
||||
bt- 30,L(done_return_value)
|
||||
#ifndef __NO_FPRS__
|
||||
bt- 29,L(fp_return_value)
|
||||
#endif
|
||||
stw %r3,0(%r30)
|
||||
bf+ 28,L(done_return_value)
|
||||
bf+ 27,L(done_return_value)
|
||||
stw %r4,4(%r30)
|
||||
mtcrf 0x02,%r31 /* cr6 */
|
||||
bf 27,L(done_return_value)
|
||||
bf 26,L(done_return_value)
|
||||
stw %r5,8(%r30)
|
||||
stw %r6,12(%r30)
|
||||
/* Fall through... */
|
||||
|
@ -145,10 +144,9 @@ L(done_return_value):
|
|||
#ifndef __NO_FPRS__
|
||||
L(fp_return_value):
|
||||
.cfi_restore_state
|
||||
bf 28,L(float_return_value)
|
||||
bf 27,L(float_return_value)
|
||||
stfd %f1,0(%r30)
|
||||
mtcrf 0x02,%r31 /* cr6 */
|
||||
bf 27,L(done_return_value)
|
||||
bf 26,L(done_return_value)
|
||||
stfd %f2,8(%r30)
|
||||
b L(done_return_value)
|
||||
L(float_return_value):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
prep_cif.c - Copyright (c) 2011, 2012 Anthony Green
|
||||
prep_cif.c - Copyright (c) 2011, 2012, 2021 Anthony Green
|
||||
Copyright (c) 1996, 1998, 2007 Red Hat, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -29,12 +29,12 @@
|
|||
|
||||
/* Round up to FFI_SIZEOF_ARG. */
|
||||
|
||||
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
|
||||
#define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG)
|
||||
|
||||
/* Perform machine independent initialization of aggregate type
|
||||
specifications. */
|
||||
|
||||
static ffi_status initialize_aggregate(ffi_type *arg)
|
||||
static ffi_status initialize_aggregate(ffi_type *arg, size_t *offsets)
|
||||
{
|
||||
ffi_type **ptr;
|
||||
|
||||
|
@ -52,13 +52,15 @@ static ffi_status initialize_aggregate(ffi_type *arg)
|
|||
while ((*ptr) != NULL)
|
||||
{
|
||||
if (UNLIKELY(((*ptr)->size == 0)
|
||||
&& (initialize_aggregate((*ptr)) != FFI_OK)))
|
||||
&& (initialize_aggregate((*ptr), NULL) != FFI_OK)))
|
||||
return FFI_BAD_TYPEDEF;
|
||||
|
||||
/* Perform a sanity check on the argument type */
|
||||
FFI_ASSERT_VALID_TYPE(*ptr);
|
||||
|
||||
arg->size = ALIGN(arg->size, (*ptr)->alignment);
|
||||
arg->size = FFI_ALIGN(arg->size, (*ptr)->alignment);
|
||||
if (offsets)
|
||||
*offsets++ = arg->size;
|
||||
arg->size += (*ptr)->size;
|
||||
|
||||
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
|
||||
|
@ -74,7 +76,7 @@ static ffi_status initialize_aggregate(ffi_type *arg)
|
|||
struct A { long a; char b; }; struct B { struct A x; char y; };
|
||||
should find y at an offset of 2*sizeof(long) and result in a
|
||||
total size of 3*sizeof(long). */
|
||||
arg->size = ALIGN (arg->size, arg->alignment);
|
||||
arg->size = FFI_ALIGN (arg->size, arg->alignment);
|
||||
|
||||
/* On some targets, the ABI defines that structures have an additional
|
||||
alignment beyond the "natural" one based on their elements. */
|
||||
|
@ -127,13 +129,16 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|||
cif->rtype = rtype;
|
||||
|
||||
cif->flags = 0;
|
||||
|
||||
#if (defined(_M_ARM64) || defined(__aarch64__)) && defined(_WIN32)
|
||||
cif->is_variadic = isvariadic;
|
||||
#endif
|
||||
#if HAVE_LONG_DOUBLE_VARIANT
|
||||
ffi_prep_types (abi);
|
||||
#endif
|
||||
|
||||
/* Initialize the return type if necessary */
|
||||
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
|
||||
if ((cif->rtype->size == 0)
|
||||
&& (initialize_aggregate(cif->rtype, NULL) != FFI_OK))
|
||||
return FFI_BAD_TYPEDEF;
|
||||
|
||||
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
@ -164,7 +169,8 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|||
{
|
||||
|
||||
/* Initialize any uninitialized aggregate type definitions */
|
||||
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
|
||||
if (((*ptr)->size == 0)
|
||||
&& (initialize_aggregate((*ptr), NULL) != FFI_OK))
|
||||
return FFI_BAD_TYPEDEF;
|
||||
|
||||
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
@ -179,7 +185,7 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|||
{
|
||||
/* Add any padding if necessary */
|
||||
if (((*ptr)->alignment - 1) & bytes)
|
||||
bytes = (unsigned)ALIGN(bytes, (*ptr)->alignment);
|
||||
bytes = (unsigned)FFI_ALIGN(bytes, (*ptr)->alignment);
|
||||
|
||||
#ifdef TILE
|
||||
if (bytes < 10 * FFI_SIZEOF_ARG &&
|
||||
|
@ -195,7 +201,7 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|||
bytes = 6*4;
|
||||
#endif
|
||||
|
||||
bytes += STACK_ARG_SIZE((*ptr)->size);
|
||||
bytes += (unsigned int)STACK_ARG_SIZE((*ptr)->size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -225,7 +231,26 @@ ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
|||
ffi_type *rtype,
|
||||
ffi_type **atypes)
|
||||
{
|
||||
return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
|
||||
ffi_status rc;
|
||||
size_t int_size = ffi_type_sint.size;
|
||||
int i;
|
||||
|
||||
rc = ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
|
||||
|
||||
if (rc != FFI_OK)
|
||||
return rc;
|
||||
|
||||
for (i = 1; i < ntotalargs; i++)
|
||||
{
|
||||
ffi_type *arg_type = atypes[i];
|
||||
if (arg_type == &ffi_type_float
|
||||
|| ((arg_type->type != FFI_TYPE_STRUCT
|
||||
&& arg_type->type != FFI_TYPE_COMPLEX)
|
||||
&& arg_type->size < int_size))
|
||||
return FFI_BAD_ARGTYPE;
|
||||
}
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
#if FFI_CLOSURES
|
||||
|
@ -240,3 +265,18 @@ ffi_prep_closure (ffi_closure* closure,
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
ffi_status
|
||||
ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets)
|
||||
{
|
||||
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
|
||||
return FFI_BAD_ABI;
|
||||
if (struct_type->type != FFI_TYPE_STRUCT)
|
||||
return FFI_BAD_TYPEDEF;
|
||||
|
||||
#if HAVE_LONG_DOUBLE_VARIANT
|
||||
ffi_prep_types (abi);
|
||||
#endif
|
||||
|
||||
return initialize_aggregate(struct_type, offsets);
|
||||
}
|
||||
|
|
|
@ -43,10 +43,10 @@ ffi_raw_size (ffi_cif *cif)
|
|||
{
|
||||
#if !FFI_NO_STRUCTS
|
||||
if ((*at)->type == FFI_TYPE_STRUCT)
|
||||
result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
|
||||
result += FFI_ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
|
||||
else
|
||||
#endif
|
||||
result += ALIGN ((*at)->size, FFI_SIZEOF_ARG);
|
||||
result += FFI_ALIGN ((*at)->size, FFI_SIZEOF_ARG);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -98,7 +98,7 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
|
|||
|
||||
default:
|
||||
*args = raw;
|
||||
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
raw += FFI_ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
|
|||
else
|
||||
{
|
||||
*args = (void*) raw;
|
||||
raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
|
||||
raw += FFI_ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
|
|||
|
||||
default:
|
||||
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
|
||||
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
raw += FFI_ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ static float_struct_info struct_passed_as_elements(call_builder *cb, ffi_type *t
|
|||
|
||||
ret.type1 = fields[0]->type;
|
||||
ret.type2 = fields[1]->type;
|
||||
ret.offset2 = ALIGN(fields[0]->size, fields[1]->alignment);
|
||||
ret.offset2 = FFI_ALIGN(fields[0]->size, fields[1]->alignment);
|
||||
ret.as_elements = 1;
|
||||
}
|
||||
|
||||
|
@ -238,8 +238,8 @@ static void marshal(call_builder *cb, ffi_type *type, int var, void *data) {
|
|||
/* variadics are aligned even in registers */
|
||||
if (type->alignment > __SIZEOF_POINTER__) {
|
||||
if (var)
|
||||
cb->used_integer = ALIGN(cb->used_integer, 2);
|
||||
cb->used_stack = (size_t *)ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
|
||||
cb->used_integer = FFI_ALIGN(cb->used_integer, 2);
|
||||
cb->used_stack = (size_t *)FFI_ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
|
||||
}
|
||||
|
||||
memcpy(realign, data, type->size);
|
||||
|
@ -286,8 +286,8 @@ static void *unmarshal(call_builder *cb, ffi_type *type, int var, void *data) {
|
|||
/* variadics are aligned even in registers */
|
||||
if (type->alignment > __SIZEOF_POINTER__) {
|
||||
if (var)
|
||||
cb->used_integer = ALIGN(cb->used_integer, 2);
|
||||
cb->used_stack = (size_t *)ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
|
||||
cb->used_integer = FFI_ALIGN(cb->used_integer, 2);
|
||||
cb->used_stack = (size_t *)FFI_ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
|
||||
}
|
||||
|
||||
if (type->size > 0)
|
||||
|
@ -334,10 +334,10 @@ ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
|
|||
/* this is a conservative estimate, assuming a complex return value and
|
||||
that all remaining arguments are long long / __int128 */
|
||||
size_t arg_bytes = cif->nargs <= 3 ? 0 :
|
||||
ALIGN(2 * sizeof(size_t) * (cif->nargs - 3), STKALIGN);
|
||||
FFI_ALIGN(2 * sizeof(size_t) * (cif->nargs - 3), STKALIGN);
|
||||
size_t rval_bytes = 0;
|
||||
if (rvalue == NULL && cif->rtype->size > 2*__SIZEOF_POINTER__)
|
||||
rval_bytes = ALIGN(cif->rtype->size, STKALIGN);
|
||||
rval_bytes = FFI_ALIGN(cif->rtype->size, STKALIGN);
|
||||
size_t alloc_size = arg_bytes + rval_bytes + sizeof(call_context);
|
||||
|
||||
/* the assembly code will deallocate all stack data at lower addresses
|
||||
|
@ -350,7 +350,7 @@ ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
|
|||
guarantee alloca alignment to at least that much */
|
||||
alloc_base = (size_t)alloca(alloc_size);
|
||||
} else {
|
||||
alloc_base = ALIGN(alloca(alloc_size + STKALIGN - 1), STKALIGN);
|
||||
alloc_base = FFI_ALIGN(alloca(alloc_size + STKALIGN - 1), STKALIGN);
|
||||
}
|
||||
|
||||
if (rval_bytes)
|
||||
|
|
|
@ -153,7 +153,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
/* FALLTHRU */
|
||||
|
||||
default:
|
||||
z = ALIGN(z, 4);
|
||||
z = FFI_ALIGN(z, 4);
|
||||
}
|
||||
bytes += z;
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
bytes += 4;
|
||||
|
||||
/* The stack must be 2 word aligned, so round bytes up appropriately. */
|
||||
bytes = ALIGN(bytes, 2 * 4);
|
||||
bytes = FFI_ALIGN(bytes, 2 * 4);
|
||||
|
||||
/* Include the call frame to prep_args. */
|
||||
bytes += 4*16 + 4*8;
|
||||
|
@ -293,7 +293,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
got to pass the return value to the callee. Otherwise ignore it. */
|
||||
if (rvalue == NULL
|
||||
&& (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
|
||||
bytes += ALIGN (cif->rtype->size, 8);
|
||||
bytes += FFI_ALIGN (cif->rtype->size, 8);
|
||||
|
||||
ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
|
|||
size_t z = t->size;
|
||||
int o, m, tt;
|
||||
|
||||
size_mask = ALIGN(size_mask, t->alignment);
|
||||
size_mask = FFI_ALIGN(size_mask, t->alignment);
|
||||
switch (t->type)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
|
@ -99,7 +99,7 @@ ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
|
|||
size_mask += z;
|
||||
}
|
||||
|
||||
size_mask = ALIGN(size_mask, outer_type->alignment);
|
||||
size_mask = FFI_ALIGN(size_mask, outer_type->alignment);
|
||||
FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
|
||||
|
||||
return size_mask;
|
||||
|
@ -284,8 +284,8 @@ ffi_prep_cif_machdep_core(ffi_cif *cif)
|
|||
flags |= SPARC_FLAG_FP_ARGS;
|
||||
break;
|
||||
}
|
||||
bytes = ALIGN(bytes, a);
|
||||
bytes += ALIGN(z, 8);
|
||||
bytes = FFI_ALIGN(bytes, a);
|
||||
bytes += FFI_ALIGN(z, 8);
|
||||
}
|
||||
|
||||
/* Sparc call frames require that space is allocated for 6 args,
|
||||
|
@ -294,7 +294,7 @@ ffi_prep_cif_machdep_core(ffi_cif *cif)
|
|||
bytes = 6 * 8;
|
||||
|
||||
/* The stack must be 2 word aligned, so round bytes up appropriately. */
|
||||
bytes = ALIGN(bytes, 16);
|
||||
bytes = FFI_ALIGN(bytes, 16);
|
||||
|
||||
/* Include the call frame to prep_args. */
|
||||
bytes += 8*16 + 8*8;
|
||||
|
@ -405,7 +405,7 @@ ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
|
|||
if (((unsigned long)argp & 15) && ty->alignment > 8)
|
||||
argp++;
|
||||
memcpy(argp, a, z);
|
||||
argp += ALIGN(z, 8) / 8;
|
||||
argp += FFI_ALIGN(z, 8) / 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -425,7 +425,7 @@ ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
FFI_ASSERT (cif->abi == FFI_V9);
|
||||
|
||||
if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
|
||||
bytes += ALIGN (cif->rtype->size, 16);
|
||||
bytes += FFI_ALIGN (cif->rtype->size, 16);
|
||||
|
||||
ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
|
||||
}
|
||||
|
@ -547,7 +547,7 @@ ffi_closure_sparc_inner_v9(ffi_cif *cif,
|
|||
a = *(void **)a;
|
||||
else
|
||||
{
|
||||
argx = argn + ALIGN (z, 8) / 8;
|
||||
argx = argn + FFI_ALIGN (z, 8) / 8;
|
||||
if (named && argn < 16)
|
||||
{
|
||||
int size_mask = ffi_struct_float_mask (ty, 0);
|
||||
|
@ -561,7 +561,7 @@ ffi_closure_sparc_inner_v9(ffi_cif *cif,
|
|||
break;
|
||||
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
argn = ALIGN (argn, 2);
|
||||
argn = FFI_ALIGN (argn, 2);
|
||||
a = (named && argn < 16 ? fpr : gpr) + argn;
|
||||
argx = argn + 2;
|
||||
break;
|
||||
|
|
729
libffi/src/tramp.c
Normal file
729
libffi/src/tramp.c
Normal file
|
@ -0,0 +1,729 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
tramp.c - Copyright (c) 2020 Madhavan T. Venkataraman
|
||||
|
||||
API and support functions for managing statically defined closure
|
||||
trampolines.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#include <fficonfig.h>
|
||||
|
||||
#ifdef FFI_EXEC_STATIC_TRAMP
|
||||
|
||||
/* -------------------------- Headers and Definitions ---------------------*/
|
||||
/*
|
||||
* Add support for other OSes later. For now, it is just Linux.
|
||||
*/
|
||||
|
||||
#if defined __linux__
|
||||
#ifdef __linux__
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <tramp.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/limits.h>
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
#endif /* __linux__ */
|
||||
|
||||
/*
|
||||
* Each architecture defines static code for a trampoline code table. The
|
||||
* trampoline code table is mapped into the address space of a process.
|
||||
*
|
||||
* The following architecture specific function returns:
|
||||
*
|
||||
* - the address of the trampoline code table in the text segment
|
||||
* - the size of each trampoline in the trampoline code table
|
||||
* - the size of the mapping for the whole trampoline code table
|
||||
*/
|
||||
void __attribute__((weak)) *ffi_tramp_arch (size_t *tramp_size,
|
||||
size_t *map_size);
|
||||
|
||||
/* ------------------------- Trampoline Data Structures --------------------*/
|
||||
|
||||
struct tramp;
|
||||
|
||||
/*
|
||||
* Trampoline table. Manages one trampoline code table and one trampoline
|
||||
* parameter table.
|
||||
*
|
||||
* prev, next Links in the global trampoline table list.
|
||||
* code_table Trampoline code table mapping.
|
||||
* parm_table Trampoline parameter table mapping.
|
||||
* array Array of trampolines malloced.
|
||||
* free List of free trampolines.
|
||||
* nfree Number of free trampolines.
|
||||
*/
|
||||
struct tramp_table
|
||||
{
|
||||
struct tramp_table *prev;
|
||||
struct tramp_table *next;
|
||||
void *code_table;
|
||||
void *parm_table;
|
||||
struct tramp *array;
|
||||
struct tramp *free;
|
||||
int nfree;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parameters for each trampoline.
|
||||
*
|
||||
* data
|
||||
* Data for the target code that the trampoline jumps to.
|
||||
* target
|
||||
* Target code that the trampoline jumps to.
|
||||
*/
|
||||
struct tramp_parm
|
||||
{
|
||||
void *data;
|
||||
void *target;
|
||||
};
|
||||
|
||||
/*
|
||||
* Trampoline structure for each trampoline.
|
||||
*
|
||||
* prev, next Links in the trampoline free list of a trampoline table.
|
||||
* table Trampoline table to which this trampoline belongs.
|
||||
* code Address of this trampoline in the code table mapping.
|
||||
* parm Address of this trampoline's parameters in the parameter
|
||||
* table mapping.
|
||||
*/
|
||||
struct tramp
|
||||
{
|
||||
struct tramp *prev;
|
||||
struct tramp *next;
|
||||
struct tramp_table *table;
|
||||
void *code;
|
||||
struct tramp_parm *parm;
|
||||
};
|
||||
|
||||
enum tramp_globals_status {
|
||||
TRAMP_GLOBALS_UNINITIALIZED = 0,
|
||||
TRAMP_GLOBALS_PASSED,
|
||||
TRAMP_GLOBALS_FAILED,
|
||||
};
|
||||
|
||||
/*
|
||||
* Trampoline globals.
|
||||
*
|
||||
* fd
|
||||
* File descriptor of binary file that contains the trampoline code table.
|
||||
* offset
|
||||
* Offset of the trampoline code table in that file.
|
||||
* text
|
||||
* Address of the trampoline code table in the text segment.
|
||||
* map_size
|
||||
* Size of the trampoline code table mapping.
|
||||
* size
|
||||
* Size of one trampoline in the trampoline code table.
|
||||
* ntramp
|
||||
* Total number of trampolines in the trampoline code table.
|
||||
* free_tables
|
||||
* List of trampoline tables that contain free trampolines.
|
||||
* nfree_tables
|
||||
* Number of trampoline tables that contain free trampolines.
|
||||
* status
|
||||
* Initialization status.
|
||||
*/
|
||||
struct tramp_globals
|
||||
{
|
||||
int fd;
|
||||
off_t offset;
|
||||
void *text;
|
||||
size_t map_size;
|
||||
size_t size;
|
||||
int ntramp;
|
||||
struct tramp_table *free_tables;
|
||||
int nfree_tables;
|
||||
enum tramp_globals_status status;
|
||||
};
|
||||
|
||||
static struct tramp_globals tramp_globals;
|
||||
|
||||
/* --------------------- Trampoline File Initialization --------------------*/
|
||||
|
||||
/*
|
||||
* The trampoline file is the file used to map the trampoline code table into
|
||||
* the address space of a process. There are two ways to get this file:
|
||||
*
|
||||
* - From the OS. E.g., on Linux, /proc/<pid>/maps lists all the memory
|
||||
* mappings for <pid>. For file-backed mappings, maps supplies the file name
|
||||
* and the file offset. Using this, we can locate the mapping that maps
|
||||
* libffi and get the path to the libffi binary. And, we can compute the
|
||||
* offset of the trampoline code table within that binary.
|
||||
*
|
||||
* - Else, if we can create a temporary file, we can write the trampoline code
|
||||
* table from the text segment into the temporary file.
|
||||
*
|
||||
* The first method is the preferred one. If the OS security subsystem
|
||||
* disallows mapping unsigned files with PROT_EXEC, then the second method
|
||||
* will fail.
|
||||
*
|
||||
* If an OS allows the trampoline code table in the text segment to be
|
||||
* directly remapped (e.g., MACH vm_remap ()), then we don't need the
|
||||
* trampoline file.
|
||||
*/
|
||||
static int tramp_table_alloc (void);
|
||||
|
||||
#if defined __linux__
|
||||
|
||||
static int
|
||||
ffi_tramp_get_libffi (void)
|
||||
{
|
||||
FILE *fp;
|
||||
char file[PATH_MAX], line[PATH_MAX+100], perm[10], dev[10];
|
||||
unsigned long start, end, offset, inode;
|
||||
uintptr_t addr = (uintptr_t) tramp_globals.text;
|
||||
int nfields, found;
|
||||
|
||||
snprintf (file, PATH_MAX, "/proc/%d/maps", getpid());
|
||||
fp = fopen (file, "r");
|
||||
if (fp == NULL)
|
||||
return 0;
|
||||
|
||||
found = 0;
|
||||
while (feof (fp) == 0) {
|
||||
if (fgets (line, sizeof (line), fp) == 0)
|
||||
break;
|
||||
|
||||
nfields = sscanf (line, "%lx-%lx %9s %lx %9s %ld %s",
|
||||
&start, &end, perm, &offset, dev, &inode, file);
|
||||
if (nfields != 7)
|
||||
continue;
|
||||
|
||||
if (addr >= start && addr < end) {
|
||||
tramp_globals.offset = offset + (addr - start);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
if (!found)
|
||||
return 0;
|
||||
|
||||
tramp_globals.fd = open (file, O_RDONLY);
|
||||
if (tramp_globals.fd == -1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Allocate a trampoline table just to make sure that the trampoline code
|
||||
* table can be mapped.
|
||||
*/
|
||||
if (!tramp_table_alloc ())
|
||||
{
|
||||
close (tramp_globals.fd);
|
||||
tramp_globals.fd = -1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#if defined __linux__
|
||||
|
||||
#if defined HAVE_MKSTEMP
|
||||
|
||||
static int
|
||||
ffi_tramp_get_temp_file (void)
|
||||
{
|
||||
char template[12] = "/tmp/XXXXXX";
|
||||
ssize_t count;
|
||||
|
||||
tramp_globals.offset = 0;
|
||||
tramp_globals.fd = mkstemp (template);
|
||||
if (tramp_globals.fd == -1)
|
||||
return 0;
|
||||
|
||||
unlink (template);
|
||||
/*
|
||||
* Write the trampoline code table into the temporary file and allocate a
|
||||
* trampoline table to make sure that the temporary file can be mapped.
|
||||
*/
|
||||
count = write(tramp_globals.fd, tramp_globals.text, tramp_globals.map_size);
|
||||
if (count == tramp_globals.map_size && tramp_table_alloc ())
|
||||
return 1;
|
||||
|
||||
close (tramp_globals.fd);
|
||||
tramp_globals.fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !defined HAVE_MKSTEMP */
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* src/closures.c contains code for finding temp file that has EXEC
|
||||
* permissions. May be, some of that code can be shared with static
|
||||
* trampolines.
|
||||
*/
|
||||
static int
|
||||
ffi_tramp_get_temp_file (void)
|
||||
{
|
||||
tramp_globals.offset = 0;
|
||||
tramp_globals.fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined HAVE_MKSTEMP */
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------ OS-specific Initialization ----------------------*/
|
||||
|
||||
#if defined __linux__
|
||||
|
||||
static int
|
||||
ffi_tramp_init_os (void)
|
||||
{
|
||||
if (ffi_tramp_get_libffi ())
|
||||
return 1;
|
||||
return ffi_tramp_get_temp_file ();
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* --------------------------- OS-specific Locking -------------------------*/
|
||||
|
||||
#if defined __linux__
|
||||
|
||||
static pthread_mutex_t tramp_globals_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void
|
||||
ffi_tramp_lock(void)
|
||||
{
|
||||
pthread_mutex_lock (&tramp_globals_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_tramp_unlock()
|
||||
{
|
||||
pthread_mutex_unlock (&tramp_globals_mutex);
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------ OS-specific Memory Mapping ----------------------*/
|
||||
|
||||
/*
|
||||
* Create a trampoline code table mapping and a trampoline parameter table
|
||||
* mapping. The two mappings must be adjacent to each other for PC-relative
|
||||
* access.
|
||||
*
|
||||
* For each trampoline in the code table, there is a corresponding parameter
|
||||
* block in the parameter table. The size of the parameter block is the same
|
||||
* as the size of the trampoline. This means that the parameter block is at
|
||||
* a fixed offset from its trampoline making it easy for a trampoline to find
|
||||
* its parameters using PC-relative access.
|
||||
*
|
||||
* The parameter block will contain a struct tramp_parm. This means that
|
||||
* sizeof (struct tramp_parm) cannot exceed the size of a parameter block.
|
||||
*/
|
||||
|
||||
#if defined __linux__
|
||||
|
||||
static int
|
||||
tramp_table_map (struct tramp_table *table)
|
||||
{
|
||||
char *addr;
|
||||
|
||||
/*
|
||||
* Create an anonymous mapping twice the map size. The top half will be used
|
||||
* for the code table. The bottom half will be used for the parameter table.
|
||||
*/
|
||||
addr = mmap (NULL, tramp_globals.map_size * 2, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Replace the top half of the anonymous mapping with the code table mapping.
|
||||
*/
|
||||
table->code_table = mmap (addr, tramp_globals.map_size, PROT_READ | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_FIXED, tramp_globals.fd, tramp_globals.offset);
|
||||
if (table->code_table == MAP_FAILED)
|
||||
{
|
||||
(void) munmap (addr, tramp_globals.map_size * 2);
|
||||
return 0;
|
||||
}
|
||||
table->parm_table = table->code_table + tramp_globals.map_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
tramp_table_unmap (struct tramp_table *table)
|
||||
{
|
||||
(void) munmap (table->code_table, tramp_globals.map_size);
|
||||
(void) munmap (table->parm_table, tramp_globals.map_size);
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------ Trampoline Initialization ----------------------*/
|
||||
|
||||
/*
|
||||
* Initialize the static trampoline feature.
|
||||
*/
|
||||
static int
|
||||
ffi_tramp_init (void)
|
||||
{
|
||||
if (tramp_globals.status == TRAMP_GLOBALS_PASSED)
|
||||
return 1;
|
||||
|
||||
if (tramp_globals.status == TRAMP_GLOBALS_FAILED)
|
||||
return 0;
|
||||
|
||||
if (ffi_tramp_arch == NULL)
|
||||
{
|
||||
tramp_globals.status = TRAMP_GLOBALS_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tramp_globals.free_tables = NULL;
|
||||
tramp_globals.nfree_tables = 0;
|
||||
|
||||
/*
|
||||
* Get trampoline code table information from the architecture.
|
||||
*/
|
||||
tramp_globals.text = ffi_tramp_arch (&tramp_globals.size,
|
||||
&tramp_globals.map_size);
|
||||
tramp_globals.ntramp = tramp_globals.map_size / tramp_globals.size;
|
||||
|
||||
if (sysconf (_SC_PAGESIZE) > tramp_globals.map_size)
|
||||
return 0;
|
||||
|
||||
if (ffi_tramp_init_os ())
|
||||
{
|
||||
tramp_globals.status = TRAMP_GLOBALS_PASSED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
tramp_globals.status = TRAMP_GLOBALS_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------- Trampoline Table functions ---------------------- */
|
||||
|
||||
/* This code assumes that malloc () is available on all OSes. */
|
||||
|
||||
static void tramp_add (struct tramp *tramp);
|
||||
|
||||
/*
|
||||
* Allocate and initialize a trampoline table.
|
||||
*/
|
||||
static int
|
||||
tramp_table_alloc (void)
|
||||
{
|
||||
struct tramp_table *table;
|
||||
struct tramp *tramp_array, *tramp;
|
||||
size_t size;
|
||||
char *code, *parm;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* If we already have tables with free trampolines, there is no need to
|
||||
* allocate a new table.
|
||||
*/
|
||||
if (tramp_globals.nfree_tables > 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Allocate a new trampoline table structure.
|
||||
*/
|
||||
table = malloc (sizeof (*table));
|
||||
if (table == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Allocate new trampoline structures.
|
||||
*/
|
||||
tramp_array = malloc (sizeof (*tramp) * tramp_globals.ntramp);
|
||||
if (tramp_array == NULL)
|
||||
goto free_table;
|
||||
|
||||
/*
|
||||
* Map a code table and a parameter table into the caller's address space.
|
||||
*/
|
||||
if (!tramp_table_map (table))
|
||||
{
|
||||
/*
|
||||
* Failed to map the code and parameter tables.
|
||||
*/
|
||||
goto free_tramp_array;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the trampoline table.
|
||||
*/
|
||||
table->array = tramp_array;
|
||||
table->free = NULL;
|
||||
table->nfree = 0;
|
||||
|
||||
/*
|
||||
* Populate the trampoline table free list. This will also add the trampoline
|
||||
* table to the global list of trampoline tables.
|
||||
*/
|
||||
size = tramp_globals.size;
|
||||
code = table->code_table;
|
||||
parm = table->parm_table;
|
||||
for (i = 0; i < tramp_globals.ntramp; i++)
|
||||
{
|
||||
tramp = &tramp_array[i];
|
||||
tramp->table = table;
|
||||
tramp->code = code;
|
||||
tramp->parm = (struct tramp_parm *) parm;
|
||||
tramp_add (tramp);
|
||||
|
||||
code += size;
|
||||
parm += size;
|
||||
}
|
||||
/* Success */
|
||||
return 1;
|
||||
|
||||
/* Failure */
|
||||
free_tramp_array:
|
||||
free (tramp_array);
|
||||
free_table:
|
||||
free (table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a trampoline table.
|
||||
*/
|
||||
static void
|
||||
tramp_table_free (struct tramp_table *table)
|
||||
{
|
||||
tramp_table_unmap (table);
|
||||
free (table->array);
|
||||
free (table);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new trampoline table to the global table list.
|
||||
*/
|
||||
static void
|
||||
tramp_table_add (struct tramp_table *table)
|
||||
{
|
||||
table->next = tramp_globals.free_tables;
|
||||
table->prev = NULL;
|
||||
if (tramp_globals.free_tables != NULL)
|
||||
tramp_globals.free_tables->prev = table;
|
||||
tramp_globals.free_tables = table;
|
||||
tramp_globals.nfree_tables++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a trampoline table from the global table list.
|
||||
*/
|
||||
static void
|
||||
tramp_table_del (struct tramp_table *table)
|
||||
{
|
||||
tramp_globals.nfree_tables--;
|
||||
if (table->prev != NULL)
|
||||
table->prev->next = table->next;
|
||||
if (table->next != NULL)
|
||||
table->next->prev = table->prev;
|
||||
if (tramp_globals.free_tables == table)
|
||||
tramp_globals.free_tables = table->next;
|
||||
}
|
||||
|
||||
/* ------------------------- Trampoline functions ------------------------- */
|
||||
|
||||
/*
|
||||
* Add a trampoline to its trampoline table.
|
||||
*/
|
||||
static void
|
||||
tramp_add (struct tramp *tramp)
|
||||
{
|
||||
struct tramp_table *table = tramp->table;
|
||||
|
||||
tramp->next = table->free;
|
||||
tramp->prev = NULL;
|
||||
if (table->free != NULL)
|
||||
table->free->prev = tramp;
|
||||
table->free = tramp;
|
||||
table->nfree++;
|
||||
|
||||
if (table->nfree == 1)
|
||||
tramp_table_add (table);
|
||||
|
||||
/*
|
||||
* We don't want to keep too many free trampoline tables lying around.
|
||||
*/
|
||||
if (table->nfree == tramp_globals.ntramp &&
|
||||
tramp_globals.nfree_tables > 1)
|
||||
{
|
||||
tramp_table_del (table);
|
||||
tramp_table_free (table);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a trampoline from its trampoline table.
|
||||
*/
|
||||
static void
|
||||
tramp_del (struct tramp *tramp)
|
||||
{
|
||||
struct tramp_table *table = tramp->table;
|
||||
|
||||
table->nfree--;
|
||||
if (tramp->prev != NULL)
|
||||
tramp->prev->next = tramp->next;
|
||||
if (tramp->next != NULL)
|
||||
tramp->next->prev = tramp->prev;
|
||||
if (table->free == tramp)
|
||||
table->free = tramp->next;
|
||||
|
||||
if (table->nfree == 0)
|
||||
tramp_table_del (table);
|
||||
}
|
||||
|
||||
/* ------------------------ Trampoline API functions ------------------------ */
|
||||
|
||||
int
|
||||
ffi_tramp_is_supported(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ffi_tramp_lock();
|
||||
ret = ffi_tramp_init ();
|
||||
ffi_tramp_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a trampoline and return its opaque address.
|
||||
*/
|
||||
void *
|
||||
ffi_tramp_alloc (int flags)
|
||||
{
|
||||
struct tramp *tramp;
|
||||
|
||||
ffi_tramp_lock();
|
||||
|
||||
if (!ffi_tramp_init () || flags != 0)
|
||||
{
|
||||
ffi_tramp_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!tramp_table_alloc ())
|
||||
{
|
||||
ffi_tramp_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tramp = tramp_globals.free_tables->free;
|
||||
tramp_del (tramp);
|
||||
|
||||
ffi_tramp_unlock();
|
||||
|
||||
return tramp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the parameters for a trampoline.
|
||||
*/
|
||||
void
|
||||
ffi_tramp_set_parms (void *arg, void *target, void *data)
|
||||
{
|
||||
struct tramp *tramp = arg;
|
||||
|
||||
ffi_tramp_lock();
|
||||
tramp->parm->target = target;
|
||||
tramp->parm->data = data;
|
||||
ffi_tramp_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the invocation address of a trampoline.
|
||||
*/
|
||||
void *
|
||||
ffi_tramp_get_addr (void *arg)
|
||||
{
|
||||
struct tramp *tramp = arg;
|
||||
void *addr;
|
||||
|
||||
ffi_tramp_lock();
|
||||
addr = tramp->code;
|
||||
ffi_tramp_unlock();
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a trampoline.
|
||||
*/
|
||||
void
|
||||
ffi_tramp_free (void *arg)
|
||||
{
|
||||
struct tramp *tramp = arg;
|
||||
|
||||
ffi_tramp_lock();
|
||||
tramp_add (tramp);
|
||||
ffi_tramp_unlock();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#else /* !FFI_EXEC_STATIC_TRAMP */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int
|
||||
ffi_tramp_is_supported(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
ffi_tramp_alloc (int flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ffi_tramp_set_parms (void *arg, void *target, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
void *
|
||||
ffi_tramp_get_addr (void *arg)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ffi_tramp_free (void *arg)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* FFI_EXEC_STATIC_TRAMP */
|
|
@ -38,6 +38,7 @@ struct struct_align_##name { \
|
|||
char c; \
|
||||
type x; \
|
||||
}; \
|
||||
FFI_EXTERN \
|
||||
maybe_const ffi_type ffi_type_##name = { \
|
||||
sizeof(type), \
|
||||
offsetof(struct struct_align_##name, x), \
|
||||
|
@ -52,6 +53,7 @@ struct struct_align_complex_##name { \
|
|||
char c; \
|
||||
_Complex type x; \
|
||||
}; \
|
||||
FFI_EXTERN \
|
||||
maybe_const ffi_type ffi_type_complex_##name = { \
|
||||
sizeof(_Complex type), \
|
||||
offsetof(struct struct_align_complex_##name, x), \
|
||||
|
@ -60,7 +62,7 @@ maybe_const ffi_type ffi_type_complex_##name = { \
|
|||
}
|
||||
|
||||
/* Size and alignment are fake here. They must not be 0. */
|
||||
const ffi_type ffi_type_void = {
|
||||
FFI_EXTERN const ffi_type ffi_type_void = {
|
||||
1, 1, FFI_TYPE_VOID, NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ ffi_prep_args (extended_cif *ecif, void *stack)
|
|||
|
||||
/* Align if necessary. */
|
||||
if ((sizeof(int) - 1) & z)
|
||||
z = ALIGN(z, sizeof(int));
|
||||
z = FFI_ALIGN(z, sizeof(int));
|
||||
}
|
||||
|
||||
p_argv++;
|
||||
|
@ -215,7 +215,7 @@ ffi_prep_closure_elfbsd (ffi_cif *cif, void **avalue, char *stackp)
|
|||
|
||||
/* Align if necessary */
|
||||
if ((sizeof (int) - 1) & z)
|
||||
z = ALIGN(z, sizeof (int));
|
||||
z = FFI_ALIGN(z, sizeof (int));
|
||||
|
||||
p_argv++;
|
||||
stackp += z;
|
||||
|
|
30
libffi/src/x86/asmnames.h
Normal file
30
libffi/src/x86/asmnames.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef ASMNAMES_H
|
||||
#define ASMNAMES_H
|
||||
|
||||
#define C2(X, Y) X ## Y
|
||||
#define C1(X, Y) C2(X, Y)
|
||||
#ifdef __USER_LABEL_PREFIX__
|
||||
# define C(X) C1(__USER_LABEL_PREFIX__, X)
|
||||
#else
|
||||
# define C(X) X
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# define L(X) C1(L, X)
|
||||
#else
|
||||
# define L(X) C1(.L, X)
|
||||
#endif
|
||||
|
||||
#if defined(__ELF__) && defined(__PIC__)
|
||||
# define PLT(X) X@PLT
|
||||
#else
|
||||
# define PLT(X) X
|
||||
#endif
|
||||
|
||||
#ifdef __ELF__
|
||||
# define ENDF(X) .type X,@function; .size X, . - X
|
||||
#else
|
||||
# define ENDF(X)
|
||||
#endif
|
||||
|
||||
#endif /* ASMNAMES_H */
|
|
@ -1,444 +0,0 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
darwin.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc.
|
||||
Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
|
||||
X86 Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __x86_64__
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
||||
.text
|
||||
|
||||
.globl _ffi_prep_args
|
||||
|
||||
.align 4
|
||||
.globl _ffi_call_SYSV
|
||||
|
||||
_ffi_call_SYSV:
|
||||
.LFB1:
|
||||
pushl %ebp
|
||||
.LCFI0:
|
||||
movl %esp,%ebp
|
||||
.LCFI1:
|
||||
subl $8,%esp
|
||||
/* 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 */
|
||||
subl $8,%esp
|
||||
pushl 12(%ebp)
|
||||
pushl %eax
|
||||
call *8(%ebp)
|
||||
|
||||
/* Return stack to previous state and call the function */
|
||||
addl $16,%esp
|
||||
|
||||
call *28(%ebp)
|
||||
|
||||
/* Load %ecx with the return type code */
|
||||
movl 20(%ebp),%ecx
|
||||
|
||||
/* Protect %esi. We're going to pop it in the epilogue. */
|
||||
pushl %esi
|
||||
|
||||
/* If the return value pointer is NULL, assume no return value. */
|
||||
cmpl $0,24(%ebp)
|
||||
jne 0f
|
||||
|
||||
/* Even if there is no space for the return value, we are
|
||||
obliged to handle floating-point values. */
|
||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
||||
jne noretval
|
||||
fstp %st(0)
|
||||
|
||||
jmp epilogue
|
||||
0:
|
||||
.align 4
|
||||
call 1f
|
||||
.Lstore_table:
|
||||
.long noretval-.Lstore_table /* FFI_TYPE_VOID */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_INT */
|
||||
.long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */
|
||||
.long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */
|
||||
.long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
|
||||
.long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */
|
||||
.long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */
|
||||
.long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */
|
||||
.long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_UINT32 */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_SINT32 */
|
||||
.long retint64-.Lstore_table /* FFI_TYPE_UINT64 */
|
||||
.long retint64-.Lstore_table /* FFI_TYPE_SINT64 */
|
||||
.long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */
|
||||
.long retint-.Lstore_table /* FFI_TYPE_POINTER */
|
||||
.long retstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */
|
||||
.long retstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */
|
||||
1:
|
||||
pop %esi
|
||||
add (%esi, %ecx, 4), %esi
|
||||
jmp *%esi
|
||||
|
||||
/* Sign/zero extend as appropriate. */
|
||||
retsint8:
|
||||
movsbl %al, %eax
|
||||
jmp retint
|
||||
|
||||
retsint16:
|
||||
movswl %ax, %eax
|
||||
jmp retint
|
||||
|
||||
retuint8:
|
||||
movzbl %al, %eax
|
||||
jmp retint
|
||||
|
||||
retuint16:
|
||||
movzwl %ax, %eax
|
||||
jmp retint
|
||||
|
||||
retfloat:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
fstps (%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retdouble:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
fstpl (%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retlongdouble:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
fstpt (%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retint64:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movl %eax,0(%ecx)
|
||||
movl %edx,4(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retstruct1b:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movb %al,0(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retstruct2b:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movw %ax,0(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retint:
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movl %eax,0(%ecx)
|
||||
|
||||
retstruct:
|
||||
/* Nothing to do! */
|
||||
|
||||
noretval:
|
||||
epilogue:
|
||||
popl %esi
|
||||
movl %ebp,%esp
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
.LFE1:
|
||||
.ffi_call_SYSV_end:
|
||||
|
||||
.align 4
|
||||
FFI_HIDDEN (ffi_closure_SYSV)
|
||||
.globl _ffi_closure_SYSV
|
||||
|
||||
_ffi_closure_SYSV:
|
||||
.LFB2:
|
||||
pushl %ebp
|
||||
.LCFI2:
|
||||
movl %esp, %ebp
|
||||
.LCFI3:
|
||||
subl $40, %esp
|
||||
leal -24(%ebp), %edx
|
||||
movl %edx, -12(%ebp) /* resp */
|
||||
leal 8(%ebp), %edx
|
||||
movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
|
||||
leal -12(%ebp), %edx
|
||||
movl %edx, (%esp) /* &resp */
|
||||
movl %ebx, 8(%esp)
|
||||
.LCFI7:
|
||||
call L_ffi_closure_SYSV_inner$stub
|
||||
movl 8(%esp), %ebx
|
||||
movl -12(%ebp), %ecx
|
||||
cmpl $FFI_TYPE_INT, %eax
|
||||
je .Lcls_retint
|
||||
|
||||
/* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
|
||||
FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
|
||||
cmpl $FFI_TYPE_UINT64, %eax
|
||||
jge 0f
|
||||
cmpl $FFI_TYPE_UINT8, %eax
|
||||
jge .Lcls_retint
|
||||
|
||||
0: cmpl $FFI_TYPE_FLOAT, %eax
|
||||
je .Lcls_retfloat
|
||||
cmpl $FFI_TYPE_DOUBLE, %eax
|
||||
je .Lcls_retdouble
|
||||
cmpl $FFI_TYPE_LONGDOUBLE, %eax
|
||||
je .Lcls_retldouble
|
||||
cmpl $FFI_TYPE_SINT64, %eax
|
||||
je .Lcls_retllong
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_1B, %eax
|
||||
je .Lcls_retstruct1b
|
||||
cmpl $FFI_TYPE_SMALL_STRUCT_2B, %eax
|
||||
je .Lcls_retstruct2b
|
||||
cmpl $FFI_TYPE_STRUCT, %eax
|
||||
je .Lcls_retstruct
|
||||
.Lcls_epilogue:
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
ret
|
||||
.Lcls_retint:
|
||||
movl (%ecx), %eax
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retfloat:
|
||||
flds (%ecx)
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retdouble:
|
||||
fldl (%ecx)
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retldouble:
|
||||
fldt (%ecx)
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retllong:
|
||||
movl (%ecx), %eax
|
||||
movl 4(%ecx), %edx
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retstruct1b:
|
||||
movsbl (%ecx), %eax
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retstruct2b:
|
||||
movswl (%ecx), %eax
|
||||
jmp .Lcls_epilogue
|
||||
.Lcls_retstruct:
|
||||
lea -8(%ebp),%esp
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
ret $4
|
||||
.LFE2:
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
||||
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
|
||||
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
|
||||
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
|
||||
#define CIF_FLAGS_OFFSET 20
|
||||
|
||||
.align 4
|
||||
FFI_HIDDEN (ffi_closure_raw_SYSV)
|
||||
.globl _ffi_closure_raw_SYSV
|
||||
|
||||
_ffi_closure_raw_SYSV:
|
||||
.LFB3:
|
||||
pushl %ebp
|
||||
.LCFI4:
|
||||
movl %esp, %ebp
|
||||
.LCFI5:
|
||||
pushl %esi
|
||||
.LCFI6:
|
||||
subl $36, %esp
|
||||
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
|
||||
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
|
||||
movl %edx, 12(%esp) /* user_data */
|
||||
leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
|
||||
movl %edx, 8(%esp) /* raw_args */
|
||||
leal -24(%ebp), %edx
|
||||
movl %edx, 4(%esp) /* &res */
|
||||
movl %esi, (%esp) /* cif */
|
||||
call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
|
||||
movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
|
||||
cmpl $FFI_TYPE_INT, %eax
|
||||
je .Lrcls_retint
|
||||
|
||||
/* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
|
||||
FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
|
||||
cmpl $FFI_TYPE_UINT64, %eax
|
||||
jge 0f
|
||||
cmpl $FFI_TYPE_UINT8, %eax
|
||||
jge .Lrcls_retint
|
||||
0:
|
||||
cmpl $FFI_TYPE_FLOAT, %eax
|
||||
je .Lrcls_retfloat
|
||||
cmpl $FFI_TYPE_DOUBLE, %eax
|
||||
je .Lrcls_retdouble
|
||||
cmpl $FFI_TYPE_LONGDOUBLE, %eax
|
||||
je .Lrcls_retldouble
|
||||
cmpl $FFI_TYPE_SINT64, %eax
|
||||
je .Lrcls_retllong
|
||||
.Lrcls_epilogue:
|
||||
addl $36, %esp
|
||||
popl %esi
|
||||
popl %ebp
|
||||
ret
|
||||
.Lrcls_retint:
|
||||
movl -24(%ebp), %eax
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retfloat:
|
||||
flds -24(%ebp)
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retdouble:
|
||||
fldl -24(%ebp)
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retldouble:
|
||||
fldt -24(%ebp)
|
||||
jmp .Lrcls_epilogue
|
||||
.Lrcls_retllong:
|
||||
movl -24(%ebp), %eax
|
||||
movl -20(%ebp), %edx
|
||||
jmp .Lrcls_epilogue
|
||||
.LFE3:
|
||||
#endif
|
||||
|
||||
.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
|
||||
L_ffi_closure_SYSV_inner$stub:
|
||||
.indirect_symbol _ffi_closure_SYSV_inner
|
||||
hlt ; hlt ; hlt ; hlt ; hlt
|
||||
|
||||
|
||||
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
|
||||
EH_frame1:
|
||||
.set L$set$0,LECIE1-LSCIE1
|
||||
.long L$set$0
|
||||
LSCIE1:
|
||||
.long 0x0
|
||||
.byte 0x1
|
||||
.ascii "zR\0"
|
||||
.byte 0x1
|
||||
.byte 0x7c
|
||||
.byte 0x8
|
||||
.byte 0x1
|
||||
.byte 0x10
|
||||
.byte 0xc
|
||||
.byte 0x5
|
||||
.byte 0x4
|
||||
.byte 0x88
|
||||
.byte 0x1
|
||||
.align 2
|
||||
LECIE1:
|
||||
.globl _ffi_call_SYSV.eh
|
||||
_ffi_call_SYSV.eh:
|
||||
LSFDE1:
|
||||
.set L$set$1,LEFDE1-LASFDE1
|
||||
.long L$set$1
|
||||
LASFDE1:
|
||||
.long LASFDE1-EH_frame1
|
||||
.long .LFB1-.
|
||||
.set L$set$2,.LFE1-.LFB1
|
||||
.long L$set$2
|
||||
.byte 0x0
|
||||
.byte 0x4
|
||||
.set L$set$3,.LCFI0-.LFB1
|
||||
.long L$set$3
|
||||
.byte 0xe
|
||||
.byte 0x8
|
||||
.byte 0x84
|
||||
.byte 0x2
|
||||
.byte 0x4
|
||||
.set L$set$4,.LCFI1-.LCFI0
|
||||
.long L$set$4
|
||||
.byte 0xd
|
||||
.byte 0x4
|
||||
.align 2
|
||||
LEFDE1:
|
||||
.globl _ffi_closure_SYSV.eh
|
||||
_ffi_closure_SYSV.eh:
|
||||
LSFDE2:
|
||||
.set L$set$5,LEFDE2-LASFDE2
|
||||
.long L$set$5
|
||||
LASFDE2:
|
||||
.long LASFDE2-EH_frame1
|
||||
.long .LFB2-.
|
||||
.set L$set$6,.LFE2-.LFB2
|
||||
.long L$set$6
|
||||
.byte 0x0
|
||||
.byte 0x4
|
||||
.set L$set$7,.LCFI2-.LFB2
|
||||
.long L$set$7
|
||||
.byte 0xe
|
||||
.byte 0x8
|
||||
.byte 0x84
|
||||
.byte 0x2
|
||||
.byte 0x4
|
||||
.set L$set$8,.LCFI3-.LCFI2
|
||||
.long L$set$8
|
||||
.byte 0xd
|
||||
.byte 0x4
|
||||
.align 2
|
||||
LEFDE2:
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
||||
.globl _ffi_closure_raw_SYSV.eh
|
||||
_ffi_closure_raw_SYSV.eh:
|
||||
LSFDE3:
|
||||
.set L$set$10,LEFDE3-LASFDE3
|
||||
.long L$set$10
|
||||
LASFDE3:
|
||||
.long LASFDE3-EH_frame1
|
||||
.long .LFB3-.
|
||||
.set L$set$11,.LFE3-.LFB3
|
||||
.long L$set$11
|
||||
.byte 0x0
|
||||
.byte 0x4
|
||||
.set L$set$12,.LCFI4-.LFB3
|
||||
.long L$set$12
|
||||
.byte 0xe
|
||||
.byte 0x8
|
||||
.byte 0x84
|
||||
.byte 0x2
|
||||
.byte 0x4
|
||||
.set L$set$13,.LCFI5-.LCFI4
|
||||
.long L$set$13
|
||||
.byte 0xd
|
||||
.byte 0x4
|
||||
.byte 0x4
|
||||
.set L$set$14,.LCFI6-.LCFI5
|
||||
.long L$set$14
|
||||
.byte 0x85
|
||||
.byte 0x3
|
||||
.align 2
|
||||
LEFDE3:
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* ifndef __x86_64__ */
|
|
@ -1,416 +0,0 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
darwin64.S - Copyright (c) 2006 Free Software Foundation, Inc.
|
||||
Copyright (c) 2008 Red Hat, Inc.
|
||||
derived from unix64.S
|
||||
|
||||
x86-64 Foreign Function Interface for Darwin.
|
||||
|
||||
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.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
||||
.file "darwin64.S"
|
||||
.text
|
||||
|
||||
/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
|
||||
void *raddr, void (*fnaddr)(void));
|
||||
|
||||
Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
|
||||
for this function. This has been allocated by ffi_call. We also
|
||||
deallocate some of the stack that has been alloca'd. */
|
||||
|
||||
.align 3
|
||||
.globl _ffi_call_unix64
|
||||
|
||||
_ffi_call_unix64:
|
||||
LUW0:
|
||||
movq (%rsp), %r10 /* Load return address. */
|
||||
leaq (%rdi, %rsi), %rax /* Find local stack base. */
|
||||
movq %rdx, (%rax) /* Save flags. */
|
||||
movq %rcx, 8(%rax) /* Save raddr. */
|
||||
movq %rbp, 16(%rax) /* Save old frame pointer. */
|
||||
movq %r10, 24(%rax) /* Relocate return address. */
|
||||
movq %rax, %rbp /* Finalize local stack frame. */
|
||||
LUW1:
|
||||
movq %rdi, %r10 /* Save a copy of the register area. */
|
||||
movq %r8, %r11 /* Save a copy of the target fn. */
|
||||
movl %r9d, %eax /* Set number of SSE registers. */
|
||||
|
||||
/* Load up all argument registers. */
|
||||
movq (%r10), %rdi
|
||||
movq 8(%r10), %rsi
|
||||
movq 16(%r10), %rdx
|
||||
movq 24(%r10), %rcx
|
||||
movq 32(%r10), %r8
|
||||
movq 40(%r10), %r9
|
||||
testl %eax, %eax
|
||||
jnz Lload_sse
|
||||
Lret_from_load_sse:
|
||||
|
||||
/* Deallocate the reg arg area. */
|
||||
leaq 176(%r10), %rsp
|
||||
|
||||
/* Call the user function. */
|
||||
call *%r11
|
||||
|
||||
/* Deallocate stack arg area; local stack frame in redzone. */
|
||||
leaq 24(%rbp), %rsp
|
||||
|
||||
movq 0(%rbp), %rcx /* Reload flags. */
|
||||
movq 8(%rbp), %rdi /* Reload raddr. */
|
||||
movq 16(%rbp), %rbp /* Reload old frame pointer. */
|
||||
LUW2:
|
||||
|
||||
/* The first byte of the flags contains the FFI_TYPE. */
|
||||
movzbl %cl, %r10d
|
||||
leaq Lstore_table(%rip), %r11
|
||||
movslq (%r11, %r10, 4), %r10
|
||||
addq %r11, %r10
|
||||
jmp *%r10
|
||||
|
||||
Lstore_table:
|
||||
.long Lst_void-Lstore_table /* FFI_TYPE_VOID */
|
||||
.long Lst_sint32-Lstore_table /* FFI_TYPE_INT */
|
||||
.long Lst_float-Lstore_table /* FFI_TYPE_FLOAT */
|
||||
.long Lst_double-Lstore_table /* FFI_TYPE_DOUBLE */
|
||||
.long Lst_ldouble-Lstore_table /* FFI_TYPE_LONGDOUBLE */
|
||||
.long Lst_uint8-Lstore_table /* FFI_TYPE_UINT8 */
|
||||
.long Lst_sint8-Lstore_table /* FFI_TYPE_SINT8 */
|
||||
.long Lst_uint16-Lstore_table /* FFI_TYPE_UINT16 */
|
||||
.long Lst_sint16-Lstore_table /* FFI_TYPE_SINT16 */
|
||||
.long Lst_uint32-Lstore_table /* FFI_TYPE_UINT32 */
|
||||
.long Lst_sint32-Lstore_table /* FFI_TYPE_SINT32 */
|
||||
.long Lst_int64-Lstore_table /* FFI_TYPE_UINT64 */
|
||||
.long Lst_int64-Lstore_table /* FFI_TYPE_SINT64 */
|
||||
.long Lst_struct-Lstore_table /* FFI_TYPE_STRUCT */
|
||||
.long Lst_int64-Lstore_table /* FFI_TYPE_POINTER */
|
||||
|
||||
.text
|
||||
.align 3
|
||||
Lst_void:
|
||||
ret
|
||||
.align 3
|
||||
Lst_uint8:
|
||||
movzbq %al, %rax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 3
|
||||
Lst_sint8:
|
||||
movsbq %al, %rax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 3
|
||||
Lst_uint16:
|
||||
movzwq %ax, %rax
|
||||
movq %rax, (%rdi)
|
||||
.align 3
|
||||
Lst_sint16:
|
||||
movswq %ax, %rax
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 3
|
||||
Lst_uint32:
|
||||
movl %eax, %eax
|
||||
movq %rax, (%rdi)
|
||||
.align 3
|
||||
Lst_sint32:
|
||||
cltq
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 3
|
||||
Lst_int64:
|
||||
movq %rax, (%rdi)
|
||||
ret
|
||||
.align 3
|
||||
Lst_float:
|
||||
movss %xmm0, (%rdi)
|
||||
ret
|
||||
.align 3
|
||||
Lst_double:
|
||||
movsd %xmm0, (%rdi)
|
||||
ret
|
||||
Lst_ldouble:
|
||||
fstpt (%rdi)
|
||||
ret
|
||||
.align 3
|
||||
Lst_struct:
|
||||
leaq -20(%rsp), %rsi /* Scratch area in redzone. */
|
||||
|
||||
/* We have to locate the values now, and since we don't want to
|
||||
write too much data into the user's return value, we spill the
|
||||
value to a 16 byte scratch area first. Bits 8, 9, and 10
|
||||
control where the values are located. Only one of the three
|
||||
bits will be set; see ffi_prep_cif_machdep for the pattern. */
|
||||
movd %xmm0, %r10
|
||||
movd %xmm1, %r11
|
||||
testl $0x100, %ecx
|
||||
cmovnz %rax, %rdx
|
||||
cmovnz %r10, %rax
|
||||
testl $0x200, %ecx
|
||||
cmovnz %r10, %rdx
|
||||
testl $0x400, %ecx
|
||||
cmovnz %r10, %rax
|
||||
cmovnz %r11, %rdx
|
||||
movq %rax, (%rsi)
|
||||
movq %rdx, 8(%rsi)
|
||||
|
||||
/* Bits 12-31 contain the true size of the structure. Copy from
|
||||
the scratch area to the true destination. */
|
||||
shrl $12, %ecx
|
||||
rep movsb
|
||||
ret
|
||||
|
||||
/* Many times we can avoid loading any SSE registers at all.
|
||||
It's not worth an indirect jump to load the exact set of
|
||||
SSE registers needed; zero or all is a good compromise. */
|
||||
.align 3
|
||||
LUW3:
|
||||
Lload_sse:
|
||||
movdqa 48(%r10), %xmm0
|
||||
movdqa 64(%r10), %xmm1
|
||||
movdqa 80(%r10), %xmm2
|
||||
movdqa 96(%r10), %xmm3
|
||||
movdqa 112(%r10), %xmm4
|
||||
movdqa 128(%r10), %xmm5
|
||||
movdqa 144(%r10), %xmm6
|
||||
movdqa 160(%r10), %xmm7
|
||||
jmp Lret_from_load_sse
|
||||
|
||||
LUW4:
|
||||
.align 3
|
||||
.globl _ffi_closure_unix64
|
||||
|
||||
_ffi_closure_unix64:
|
||||
LUW5:
|
||||
/* The carry flag is set by the trampoline iff SSE registers
|
||||
are used. Don't clobber it before the branch instruction. */
|
||||
leaq -200(%rsp), %rsp
|
||||
LUW6:
|
||||
movq %rdi, (%rsp)
|
||||
movq %rsi, 8(%rsp)
|
||||
movq %rdx, 16(%rsp)
|
||||
movq %rcx, 24(%rsp)
|
||||
movq %r8, 32(%rsp)
|
||||
movq %r9, 40(%rsp)
|
||||
jc Lsave_sse
|
||||
Lret_from_save_sse:
|
||||
|
||||
movq %r10, %rdi
|
||||
leaq 176(%rsp), %rsi
|
||||
movq %rsp, %rdx
|
||||
leaq 208(%rsp), %rcx
|
||||
call _ffi_closure_unix64_inner
|
||||
|
||||
/* Deallocate stack frame early; return value is now in redzone. */
|
||||
addq $200, %rsp
|
||||
LUW7:
|
||||
|
||||
/* The first byte of the return value contains the FFI_TYPE. */
|
||||
movzbl %al, %r10d
|
||||
leaq Lload_table(%rip), %r11
|
||||
movslq (%r11, %r10, 4), %r10
|
||||
addq %r11, %r10
|
||||
jmp *%r10
|
||||
|
||||
Lload_table:
|
||||
.long Lld_void-Lload_table /* FFI_TYPE_VOID */
|
||||
.long Lld_int32-Lload_table /* FFI_TYPE_INT */
|
||||
.long Lld_float-Lload_table /* FFI_TYPE_FLOAT */
|
||||
.long Lld_double-Lload_table /* FFI_TYPE_DOUBLE */
|
||||
.long Lld_ldouble-Lload_table /* FFI_TYPE_LONGDOUBLE */
|
||||
.long Lld_int8-Lload_table /* FFI_TYPE_UINT8 */
|
||||
.long Lld_int8-Lload_table /* FFI_TYPE_SINT8 */
|
||||
.long Lld_int16-Lload_table /* FFI_TYPE_UINT16 */
|
||||
.long Lld_int16-Lload_table /* FFI_TYPE_SINT16 */
|
||||
.long Lld_int32-Lload_table /* FFI_TYPE_UINT32 */
|
||||
.long Lld_int32-Lload_table /* FFI_TYPE_SINT32 */
|
||||
.long Lld_int64-Lload_table /* FFI_TYPE_UINT64 */
|
||||
.long Lld_int64-Lload_table /* FFI_TYPE_SINT64 */
|
||||
.long Lld_struct-Lload_table /* FFI_TYPE_STRUCT */
|
||||
.long Lld_int64-Lload_table /* FFI_TYPE_POINTER */
|
||||
|
||||
.text
|
||||
.align 3
|
||||
Lld_void:
|
||||
ret
|
||||
.align 3
|
||||
Lld_int8:
|
||||
movzbl -24(%rsp), %eax
|
||||
ret
|
||||
.align 3
|
||||
Lld_int16:
|
||||
movzwl -24(%rsp), %eax
|
||||
ret
|
||||
.align 3
|
||||
Lld_int32:
|
||||
movl -24(%rsp), %eax
|
||||
ret
|
||||
.align 3
|
||||
Lld_int64:
|
||||
movq -24(%rsp), %rax
|
||||
ret
|
||||
.align 3
|
||||
Lld_float:
|
||||
movss -24(%rsp), %xmm0
|
||||
ret
|
||||
.align 3
|
||||
Lld_double:
|
||||
movsd -24(%rsp), %xmm0
|
||||
ret
|
||||
.align 3
|
||||
Lld_ldouble:
|
||||
fldt -24(%rsp)
|
||||
ret
|
||||
.align 3
|
||||
Lld_struct:
|
||||
/* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
|
||||
%rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading
|
||||
both rdx and xmm1 with the second word. For the remaining,
|
||||
bit 8 set means xmm0 gets the second word, and bit 9 means
|
||||
that rax gets the second word. */
|
||||
movq -24(%rsp), %rcx
|
||||
movq -16(%rsp), %rdx
|
||||
movq -16(%rsp), %xmm1
|
||||
testl $0x100, %eax
|
||||
cmovnz %rdx, %rcx
|
||||
movd %rcx, %xmm0
|
||||
testl $0x200, %eax
|
||||
movq -24(%rsp), %rax
|
||||
cmovnz %rdx, %rax
|
||||
ret
|
||||
|
||||
/* See the comment above Lload_sse; the same logic applies here. */
|
||||
.align 3
|
||||
LUW8:
|
||||
Lsave_sse:
|
||||
movdqa %xmm0, 48(%rsp)
|
||||
movdqa %xmm1, 64(%rsp)
|
||||
movdqa %xmm2, 80(%rsp)
|
||||
movdqa %xmm3, 96(%rsp)
|
||||
movdqa %xmm4, 112(%rsp)
|
||||
movdqa %xmm5, 128(%rsp)
|
||||
movdqa %xmm6, 144(%rsp)
|
||||
movdqa %xmm7, 160(%rsp)
|
||||
jmp Lret_from_save_sse
|
||||
|
||||
LUW9:
|
||||
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
|
||||
EH_frame1:
|
||||
.set L$set$0,LECIE1-LSCIE1 /* CIE Length */
|
||||
.long L$set$0
|
||||
LSCIE1:
|
||||
.long 0x0 /* CIE Identifier Tag */
|
||||
.byte 0x1 /* CIE Version */
|
||||
.ascii "zR\0" /* CIE Augmentation */
|
||||
.byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
|
||||
.byte 0x78 /* sleb128 -8; CIE Data Alignment Factor */
|
||||
.byte 0x10 /* CIE RA Column */
|
||||
.byte 0x1 /* uleb128 0x1; Augmentation size */
|
||||
.byte 0x10 /* FDE Encoding (pcrel sdata4) */
|
||||
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
|
||||
.byte 0x7 /* uleb128 0x7 */
|
||||
.byte 0x8 /* uleb128 0x8 */
|
||||
.byte 0x90 /* DW_CFA_offset, column 0x10 */
|
||||
.byte 0x1
|
||||
.align 3
|
||||
LECIE1:
|
||||
.globl _ffi_call_unix64.eh
|
||||
_ffi_call_unix64.eh:
|
||||
LSFDE1:
|
||||
.set L$set$1,LEFDE1-LASFDE1 /* FDE Length */
|
||||
.long L$set$1
|
||||
LASFDE1:
|
||||
.long LASFDE1-EH_frame1 /* FDE CIE offset */
|
||||
.quad LUW0-. /* FDE initial location */
|
||||
.set L$set$2,LUW4-LUW0 /* FDE address range */
|
||||
.quad L$set$2
|
||||
.byte 0x0 /* Augmentation size */
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.set L$set$3,LUW1-LUW0
|
||||
.long L$set$3
|
||||
|
||||
/* New stack frame based off rbp. This is a itty bit of unwind
|
||||
trickery in that the CFA *has* changed. There is no easy way
|
||||
to describe it correctly on entry to the function. Fortunately,
|
||||
it doesn't matter too much since at all points we can correctly
|
||||
unwind back to ffi_call. Note that the location to which we
|
||||
moved the return address is (the new) CFA-8, so from the
|
||||
perspective of the unwind info, it hasn't moved. */
|
||||
.byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */
|
||||
.byte 0x6
|
||||
.byte 0x20
|
||||
.byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */
|
||||
.byte 0x2
|
||||
.byte 0xa /* DW_CFA_remember_state */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.set L$set$4,LUW2-LUW1
|
||||
.long L$set$4
|
||||
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
|
||||
.byte 0x7
|
||||
.byte 0x8
|
||||
.byte 0xc0+6 /* DW_CFA_restore, %rbp */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.set L$set$5,LUW3-LUW2
|
||||
.long L$set$5
|
||||
.byte 0xb /* DW_CFA_restore_state */
|
||||
|
||||
.align 3
|
||||
LEFDE1:
|
||||
.globl _ffi_closure_unix64.eh
|
||||
_ffi_closure_unix64.eh:
|
||||
LSFDE3:
|
||||
.set L$set$6,LEFDE3-LASFDE3 /* FDE Length */
|
||||
.long L$set$6
|
||||
LASFDE3:
|
||||
.long LASFDE3-EH_frame1 /* FDE CIE offset */
|
||||
.quad LUW5-. /* FDE initial location */
|
||||
.set L$set$7,LUW9-LUW5 /* FDE address range */
|
||||
.quad L$set$7
|
||||
.byte 0x0 /* Augmentation size */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.set L$set$8,LUW6-LUW5
|
||||
.long L$set$8
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset */
|
||||
.byte 208,1 /* uleb128 208 */
|
||||
.byte 0xa /* DW_CFA_remember_state */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.set L$set$9,LUW7-LUW6
|
||||
.long L$set$9
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset */
|
||||
.byte 0x8
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.set L$set$10,LUW8-LUW7
|
||||
.long L$set$10
|
||||
.byte 0xb /* DW_CFA_restore_state */
|
||||
|
||||
.align 3
|
||||
LEFDE3:
|
||||
.subsections_via_symbols
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,643 +0,0 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi64.c - Copyright (c) 20011 Anthony Green
|
||||
Copyright (c) 2008, 2010 Red Hat, Inc.
|
||||
Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de>
|
||||
|
||||
x86-64 Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define MAX_GPR_REGS 6
|
||||
#define MAX_SSE_REGS 8
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#define UINT128 __m128
|
||||
#else
|
||||
#define UINT128 __int128_t
|
||||
#endif
|
||||
|
||||
struct register_args
|
||||
{
|
||||
/* Registers for argument passing. */
|
||||
UINT64 gpr[MAX_GPR_REGS];
|
||||
UINT128 sse[MAX_SSE_REGS];
|
||||
};
|
||||
|
||||
extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
|
||||
void *raddr, void (*fnaddr)(void), unsigned ssecount);
|
||||
|
||||
/* All reference to register classes here is identical to the code in
|
||||
gcc/config/i386/i386.c. Do *not* change one without the other. */
|
||||
|
||||
/* Register class used for passing given 64bit part of the argument.
|
||||
These represent classes as documented by the PS ABI, with the
|
||||
exception of SSESF, SSEDF classes, that are basically SSE class,
|
||||
just gcc will use SF or DFmode move instead of DImode to avoid
|
||||
reformatting penalties.
|
||||
|
||||
Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
|
||||
whenever possible (upper half does contain padding). */
|
||||
enum x86_64_reg_class
|
||||
{
|
||||
X86_64_NO_CLASS,
|
||||
X86_64_INTEGER_CLASS,
|
||||
X86_64_INTEGERSI_CLASS,
|
||||
X86_64_SSE_CLASS,
|
||||
X86_64_SSESF_CLASS,
|
||||
X86_64_SSEDF_CLASS,
|
||||
X86_64_SSEUP_CLASS,
|
||||
X86_64_X87_CLASS,
|
||||
X86_64_X87UP_CLASS,
|
||||
X86_64_COMPLEX_X87_CLASS,
|
||||
X86_64_MEMORY_CLASS
|
||||
};
|
||||
|
||||
#define MAX_CLASSES 4
|
||||
|
||||
#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
|
||||
|
||||
/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
|
||||
of this code is to classify each 8bytes of incoming argument by the register
|
||||
class and assign registers accordingly. */
|
||||
|
||||
/* Return the union class of CLASS1 and CLASS2.
|
||||
See the x86-64 PS ABI for details. */
|
||||
|
||||
static enum x86_64_reg_class
|
||||
merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
|
||||
{
|
||||
/* Rule #1: If both classes are equal, this is the resulting class. */
|
||||
if (class1 == class2)
|
||||
return class1;
|
||||
|
||||
/* Rule #2: If one of the classes is NO_CLASS, the resulting class is
|
||||
the other class. */
|
||||
if (class1 == X86_64_NO_CLASS)
|
||||
return class2;
|
||||
if (class2 == X86_64_NO_CLASS)
|
||||
return class1;
|
||||
|
||||
/* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
|
||||
if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
|
||||
return X86_64_MEMORY_CLASS;
|
||||
|
||||
/* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
|
||||
if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
|
||||
|| (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
|
||||
return X86_64_INTEGERSI_CLASS;
|
||||
if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
|
||||
|| class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
|
||||
return X86_64_INTEGER_CLASS;
|
||||
|
||||
/* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
|
||||
MEMORY is used. */
|
||||
if (class1 == X86_64_X87_CLASS
|
||||
|| class1 == X86_64_X87UP_CLASS
|
||||
|| class1 == X86_64_COMPLEX_X87_CLASS
|
||||
|| class2 == X86_64_X87_CLASS
|
||||
|| class2 == X86_64_X87UP_CLASS
|
||||
|| class2 == X86_64_COMPLEX_X87_CLASS)
|
||||
return X86_64_MEMORY_CLASS;
|
||||
|
||||
/* Rule #6: Otherwise class SSE is used. */
|
||||
return X86_64_SSE_CLASS;
|
||||
}
|
||||
|
||||
/* Classify the argument of type TYPE and mode MODE.
|
||||
CLASSES will be filled by the register class used to pass each word
|
||||
of the operand. The number of words is returned. In case the parameter
|
||||
should be passed in memory, 0 is returned. As a special case for zero
|
||||
sized containers, classes[0] will be NO_CLASS and 1 is returned.
|
||||
|
||||
See the x86-64 PS ABI for details.
|
||||
*/
|
||||
static int
|
||||
classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
||||
size_t byte_offset)
|
||||
{
|
||||
switch (type->type)
|
||||
{
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_POINTER:
|
||||
{
|
||||
int size = byte_offset + type->size;
|
||||
|
||||
if (size <= 4)
|
||||
{
|
||||
classes[0] = X86_64_INTEGERSI_CLASS;
|
||||
return 1;
|
||||
}
|
||||
else if (size <= 8)
|
||||
{
|
||||
classes[0] = X86_64_INTEGER_CLASS;
|
||||
return 1;
|
||||
}
|
||||
else if (size <= 12)
|
||||
{
|
||||
classes[0] = X86_64_INTEGER_CLASS;
|
||||
classes[1] = X86_64_INTEGERSI_CLASS;
|
||||
return 2;
|
||||
}
|
||||
else if (size <= 16)
|
||||
{
|
||||
classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
FFI_ASSERT (0);
|
||||
}
|
||||
case FFI_TYPE_FLOAT:
|
||||
if (!(byte_offset % 8))
|
||||
classes[0] = X86_64_SSESF_CLASS;
|
||||
else
|
||||
classes[0] = X86_64_SSE_CLASS;
|
||||
return 1;
|
||||
case FFI_TYPE_DOUBLE:
|
||||
classes[0] = X86_64_SSEDF_CLASS;
|
||||
return 1;
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
classes[0] = X86_64_X87_CLASS;
|
||||
classes[1] = X86_64_X87UP_CLASS;
|
||||
return 2;
|
||||
case FFI_TYPE_STRUCT:
|
||||
{
|
||||
const int UNITS_PER_WORD = 8;
|
||||
int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
|
||||
ffi_type **ptr;
|
||||
int i;
|
||||
enum x86_64_reg_class subclasses[MAX_CLASSES];
|
||||
|
||||
/* If the struct is larger than 32 bytes, pass it on the stack. */
|
||||
if (type->size > 32)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < words; i++)
|
||||
classes[i] = X86_64_NO_CLASS;
|
||||
|
||||
/* Zero sized arrays or structures are NO_CLASS. We return 0 to
|
||||
signalize memory class, so handle it as special case. */
|
||||
if (!words)
|
||||
{
|
||||
classes[0] = X86_64_NO_CLASS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Merge the fields of structure. */
|
||||
for (ptr = type->elements; *ptr != NULL; ptr++)
|
||||
{
|
||||
int num;
|
||||
|
||||
byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
|
||||
|
||||
num = classify_argument (*ptr, subclasses, byte_offset % 8);
|
||||
if (num == 0)
|
||||
return 0;
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
int pos = byte_offset / 8;
|
||||
classes[i + pos] =
|
||||
merge_classes (subclasses[i], classes[i + pos]);
|
||||
}
|
||||
|
||||
byte_offset += (*ptr)->size;
|
||||
}
|
||||
|
||||
if (words > 2)
|
||||
{
|
||||
/* When size > 16 bytes, if the first one isn't
|
||||
X86_64_SSE_CLASS or any other ones aren't
|
||||
X86_64_SSEUP_CLASS, everything should be passed in
|
||||
memory. */
|
||||
if (classes[0] != X86_64_SSE_CLASS)
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < words; i++)
|
||||
if (classes[i] != X86_64_SSEUP_CLASS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Final merger cleanup. */
|
||||
for (i = 0; i < words; i++)
|
||||
{
|
||||
/* If one class is MEMORY, everything should be passed in
|
||||
memory. */
|
||||
if (classes[i] == X86_64_MEMORY_CLASS)
|
||||
return 0;
|
||||
|
||||
/* The X86_64_SSEUP_CLASS should be always preceded by
|
||||
X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
|
||||
if (classes[i] == X86_64_SSEUP_CLASS
|
||||
&& classes[i - 1] != X86_64_SSE_CLASS
|
||||
&& classes[i - 1] != X86_64_SSEUP_CLASS)
|
||||
{
|
||||
/* The first one should never be X86_64_SSEUP_CLASS. */
|
||||
FFI_ASSERT (i != 0);
|
||||
classes[i] = X86_64_SSE_CLASS;
|
||||
}
|
||||
|
||||
/* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
|
||||
everything should be passed in memory. */
|
||||
if (classes[i] == X86_64_X87UP_CLASS
|
||||
&& (classes[i - 1] != X86_64_X87_CLASS))
|
||||
{
|
||||
/* The first one should never be X86_64_X87UP_CLASS. */
|
||||
FFI_ASSERT (i != 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return words;
|
||||
}
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
}
|
||||
return 0; /* Never reached. */
|
||||
}
|
||||
|
||||
/* Examine the argument and return set number of register required in each
|
||||
class. Return zero iff parameter should be passed in memory, otherwise
|
||||
the number of registers. */
|
||||
|
||||
static int
|
||||
examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
|
||||
_Bool in_return, int *pngpr, int *pnsse)
|
||||
{
|
||||
int i, n, ngpr, nsse;
|
||||
|
||||
n = classify_argument (type, classes, 0);
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
ngpr = nsse = 0;
|
||||
for (i = 0; i < n; ++i)
|
||||
switch (classes[i])
|
||||
{
|
||||
case X86_64_INTEGER_CLASS:
|
||||
case X86_64_INTEGERSI_CLASS:
|
||||
ngpr++;
|
||||
break;
|
||||
case X86_64_SSE_CLASS:
|
||||
case X86_64_SSESF_CLASS:
|
||||
case X86_64_SSEDF_CLASS:
|
||||
nsse++;
|
||||
break;
|
||||
case X86_64_NO_CLASS:
|
||||
case X86_64_SSEUP_CLASS:
|
||||
break;
|
||||
case X86_64_X87_CLASS:
|
||||
case X86_64_X87UP_CLASS:
|
||||
case X86_64_COMPLEX_X87_CLASS:
|
||||
return in_return != 0;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
*pngpr = ngpr;
|
||||
*pnsse = nsse;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing. */
|
||||
|
||||
ffi_status
|
||||
ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
{
|
||||
int gprcount, ssecount, i, avn, n, ngpr, nsse, flags;
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
size_t bytes;
|
||||
|
||||
gprcount = ssecount = 0;
|
||||
|
||||
flags = cif->rtype->type;
|
||||
if (flags != FFI_TYPE_VOID)
|
||||
{
|
||||
n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
|
||||
if (n == 0)
|
||||
{
|
||||
/* The return value is passed in memory. A pointer to that
|
||||
memory is the first argument. Allocate a register for it. */
|
||||
gprcount++;
|
||||
/* We don't have to do anything in asm for the return. */
|
||||
flags = FFI_TYPE_VOID;
|
||||
}
|
||||
else if (flags == FFI_TYPE_STRUCT)
|
||||
{
|
||||
/* Mark which registers the result appears in. */
|
||||
_Bool sse0 = SSE_CLASS_P (classes[0]);
|
||||
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
|
||||
if (sse0 && !sse1)
|
||||
flags |= 1 << 8;
|
||||
else if (!sse0 && sse1)
|
||||
flags |= 1 << 9;
|
||||
else if (sse0 && sse1)
|
||||
flags |= 1 << 10;
|
||||
/* Mark the true size of the structure. */
|
||||
flags |= cif->rtype->size << 12;
|
||||
}
|
||||
}
|
||||
|
||||
/* Go over all arguments and determine the way they should be passed.
|
||||
If it's in a register and there is space for it, let that be so. If
|
||||
not, add it's size to the stack byte count. */
|
||||
for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
|
||||
{
|
||||
if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
|
||||
|| gprcount + ngpr > MAX_GPR_REGS
|
||||
|| ssecount + nsse > MAX_SSE_REGS)
|
||||
{
|
||||
long align = cif->arg_types[i]->alignment;
|
||||
|
||||
if (align < 8)
|
||||
align = 8;
|
||||
|
||||
bytes = ALIGN (bytes, align);
|
||||
bytes += cif->arg_types[i]->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
gprcount += ngpr;
|
||||
ssecount += nsse;
|
||||
}
|
||||
}
|
||||
if (ssecount)
|
||||
flags |= 1 << 11;
|
||||
cif->flags = flags;
|
||||
cif->bytes = ALIGN (bytes, 8);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
char *stack, *argp;
|
||||
ffi_type **arg_types;
|
||||
int gprcount, ssecount, ngpr, nsse, i, avn;
|
||||
_Bool ret_in_memory;
|
||||
struct register_args *reg_args;
|
||||
|
||||
/* Can't call 32-bit mode from 64-bit mode. */
|
||||
FFI_ASSERT (cif->abi == FFI_UNIX64);
|
||||
|
||||
/* If the return value is a struct and we don't have a return value
|
||||
address then we need to make one. Note the setting of flags to
|
||||
VOID above in ffi_prep_cif_machdep. */
|
||||
ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
|
||||
&& (cif->flags & 0xff) == FFI_TYPE_VOID);
|
||||
if (rvalue == NULL && ret_in_memory)
|
||||
rvalue = alloca (cif->rtype->size);
|
||||
|
||||
/* Allocate the space for the arguments, plus 4 words of temp space. */
|
||||
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
|
||||
reg_args = (struct register_args *) stack;
|
||||
argp = stack + sizeof (struct register_args);
|
||||
|
||||
gprcount = ssecount = 0;
|
||||
|
||||
/* If the return value is passed in memory, add the pointer as the
|
||||
first integer argument. */
|
||||
if (ret_in_memory)
|
||||
reg_args->gpr[gprcount++] = (unsigned long) rvalue;
|
||||
|
||||
avn = cif->nargs;
|
||||
arg_types = cif->arg_types;
|
||||
|
||||
for (i = 0; i < avn; ++i)
|
||||
{
|
||||
size_t size = arg_types[i]->size;
|
||||
int n;
|
||||
|
||||
n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
|
||||
if (n == 0
|
||||
|| gprcount + ngpr > MAX_GPR_REGS
|
||||
|| ssecount + nsse > MAX_SSE_REGS)
|
||||
{
|
||||
long align = arg_types[i]->alignment;
|
||||
|
||||
/* Stack arguments are *always* at least 8 byte aligned. */
|
||||
if (align < 8)
|
||||
align = 8;
|
||||
|
||||
/* Pass this argument in memory. */
|
||||
argp = (void *) ALIGN (argp, align);
|
||||
memcpy (argp, avalue[i], size);
|
||||
argp += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The argument is passed entirely in registers. */
|
||||
char *a = (char *) avalue[i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < n; j++, a += 8, size -= 8)
|
||||
{
|
||||
switch (classes[j])
|
||||
{
|
||||
case X86_64_INTEGER_CLASS:
|
||||
case X86_64_INTEGERSI_CLASS:
|
||||
reg_args->gpr[gprcount] = 0;
|
||||
memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8);
|
||||
gprcount++;
|
||||
break;
|
||||
case X86_64_SSE_CLASS:
|
||||
case X86_64_SSEDF_CLASS:
|
||||
reg_args->sse[ssecount++] = *(UINT64 *) a;
|
||||
break;
|
||||
case X86_64_SSESF_CLASS:
|
||||
reg_args->sse[ssecount++] = *(UINT32 *) a;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
|
||||
cif->flags, rvalue, fn, ssecount);
|
||||
}
|
||||
|
||||
|
||||
extern void ffi_closure_unix64(void);
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
volatile unsigned short *tramp;
|
||||
|
||||
/* Sanity check on the cif ABI. */
|
||||
{
|
||||
int abi = cif->abi;
|
||||
if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
|
||||
return FFI_BAD_ABI;
|
||||
}
|
||||
|
||||
tramp = (volatile unsigned short *) &closure->tramp[0];
|
||||
|
||||
tramp[0] = 0xbb49; /* mov <code>, %r11 */
|
||||
*((unsigned long long * volatile) &tramp[1])
|
||||
= (unsigned long) ffi_closure_unix64;
|
||||
tramp[5] = 0xba49; /* mov <data>, %r10 */
|
||||
*((unsigned long long * volatile) &tramp[6])
|
||||
= (unsigned long) codeloc;
|
||||
|
||||
/* Set the carry bit iff the function uses any sse registers.
|
||||
This is clc or stc, together with the first byte of the jmp. */
|
||||
tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
|
||||
|
||||
tramp[11] = 0xe3ff; /* jmp *%r11 */
|
||||
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
closure->user_data = user_data;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
int
|
||||
ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
|
||||
struct register_args *reg_args, char *argp)
|
||||
{
|
||||
ffi_cif *cif;
|
||||
void **avalue;
|
||||
ffi_type **arg_types;
|
||||
long i, avn;
|
||||
int gprcount, ssecount, ngpr, nsse;
|
||||
int ret;
|
||||
|
||||
cif = closure->cif;
|
||||
avalue = alloca(cif->nargs * sizeof(void *));
|
||||
gprcount = ssecount = 0;
|
||||
|
||||
ret = cif->rtype->type;
|
||||
if (ret != FFI_TYPE_VOID)
|
||||
{
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
|
||||
if (n == 0)
|
||||
{
|
||||
/* The return value goes in memory. Arrange for the closure
|
||||
return value to go directly back to the original caller. */
|
||||
rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++];
|
||||
/* We don't have to do anything in asm for the return. */
|
||||
ret = FFI_TYPE_VOID;
|
||||
}
|
||||
else if (ret == FFI_TYPE_STRUCT && n == 2)
|
||||
{
|
||||
/* Mark which register the second word of the structure goes in. */
|
||||
_Bool sse0 = SSE_CLASS_P (classes[0]);
|
||||
_Bool sse1 = SSE_CLASS_P (classes[1]);
|
||||
if (!sse0 && sse1)
|
||||
ret |= 1 << 8;
|
||||
else if (sse0 && !sse1)
|
||||
ret |= 1 << 9;
|
||||
}
|
||||
}
|
||||
|
||||
avn = cif->nargs;
|
||||
arg_types = cif->arg_types;
|
||||
|
||||
for (i = 0; i < avn; ++i)
|
||||
{
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
int n;
|
||||
|
||||
n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
|
||||
if (n == 0
|
||||
|| gprcount + ngpr > MAX_GPR_REGS
|
||||
|| ssecount + nsse > MAX_SSE_REGS)
|
||||
{
|
||||
long align = arg_types[i]->alignment;
|
||||
|
||||
/* Stack arguments are *always* at least 8 byte aligned. */
|
||||
if (align < 8)
|
||||
align = 8;
|
||||
|
||||
/* Pass this argument in memory. */
|
||||
argp = (void *) ALIGN (argp, align);
|
||||
avalue[i] = argp;
|
||||
argp += arg_types[i]->size;
|
||||
}
|
||||
/* If the argument is in a single register, or two consecutive
|
||||
integer registers, then we can use that address directly. */
|
||||
else if (n == 1
|
||||
|| (n == 2 && !(SSE_CLASS_P (classes[0])
|
||||
|| SSE_CLASS_P (classes[1]))))
|
||||
{
|
||||
/* The argument is in a single register. */
|
||||
if (SSE_CLASS_P (classes[0]))
|
||||
{
|
||||
avalue[i] = ®_args->sse[ssecount];
|
||||
ssecount += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
avalue[i] = ®_args->gpr[gprcount];
|
||||
gprcount += n;
|
||||
}
|
||||
}
|
||||
/* Otherwise, allocate space to make them consecutive. */
|
||||
else
|
||||
{
|
||||
char *a = alloca (16);
|
||||
int j;
|
||||
|
||||
avalue[i] = a;
|
||||
for (j = 0; j < n; j++, a += 8)
|
||||
{
|
||||
if (SSE_CLASS_P (classes[j]))
|
||||
memcpy (a, ®_args->sse[ssecount++], 8);
|
||||
else
|
||||
memcpy (a, ®_args->gpr[gprcount++], 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the closure. */
|
||||
closure->fun (cif, rvalue, avalue, closure->user_data);
|
||||
|
||||
/* Tell assembly how to perform return type promotions. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,843 +0,0 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
|
||||
Copyright (c) 2002 Ranjit Mathew
|
||||
Copyright (c) 2002 Bo Thorsen
|
||||
Copyright (c) 2002 Roger Sayle
|
||||
Copyright (C) 2008, 2010 Free Software Foundation, Inc.
|
||||
|
||||
x86 Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#if !defined(__x86_64__) || defined(_WIN64) || defined(__CYGWIN__)
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#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)
|
||||
{
|
||||
register unsigned int i;
|
||||
register void **p_argv;
|
||||
register char *argp;
|
||||
register ffi_type **p_arg;
|
||||
#ifdef X86_WIN32
|
||||
size_t p_stack_args[2];
|
||||
void *p_stack_data[2];
|
||||
char *argp2 = stack;
|
||||
int stack_args_count = 0;
|
||||
int cabi = ecif->cif->abi;
|
||||
#endif
|
||||
|
||||
argp = stack;
|
||||
|
||||
if ((ecif->cif->flags == FFI_TYPE_STRUCT
|
||||
|| ecif->cif->flags == FFI_TYPE_MS_STRUCT)
|
||||
#ifdef X86_WIN64
|
||||
&& (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
|
||||
&& ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
*(void **) argp = ecif->rvalue;
|
||||
#ifdef X86_WIN32
|
||||
/* For fastcall/thiscall this is first register-passed
|
||||
argument. */
|
||||
if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
|
||||
{
|
||||
p_stack_args[stack_args_count] = sizeof (void*);
|
||||
p_stack_data[stack_args_count] = argp;
|
||||
++stack_args_count;
|
||||
}
|
||||
#endif
|
||||
argp += sizeof(void*);
|
||||
}
|
||||
|
||||
p_argv = ecif->avalue;
|
||||
|
||||
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
||||
i != 0;
|
||||
i--, p_arg++)
|
||||
{
|
||||
size_t z;
|
||||
|
||||
/* Align if necessary */
|
||||
if ((sizeof(void*) - 1) & (size_t) argp)
|
||||
argp = (char *) ALIGN(argp, sizeof(void*));
|
||||
|
||||
z = (*p_arg)->size;
|
||||
#ifdef X86_WIN64
|
||||
if (z > sizeof(ffi_arg)
|
||||
|| ((*p_arg)->type == FFI_TYPE_STRUCT
|
||||
&& (z != 1 && z != 2 && z != 4 && z != 8))
|
||||
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
|
||||
|| ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
z = sizeof(ffi_arg);
|
||||
*(void **)argp = *p_argv;
|
||||
}
|
||||
else if ((*p_arg)->type == FFI_TYPE_FLOAT)
|
||||
{
|
||||
memcpy(argp, *p_argv, z);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (z < sizeof(ffi_arg))
|
||||
{
|
||||
z = sizeof(ffi_arg);
|
||||
switch ((*p_arg)->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
*(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
*(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
*(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT16:
|
||||
*(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT32:
|
||||
*(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT32:
|
||||
*(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
*(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
|
||||
break;
|
||||
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(argp, *p_argv, z);
|
||||
}
|
||||
|
||||
#ifdef X86_WIN32
|
||||
/* For thiscall/fastcall convention register-passed arguments
|
||||
are the first two none-floating-point arguments with a size
|
||||
smaller or equal to sizeof (void*). */
|
||||
if ((cabi == FFI_THISCALL && stack_args_count < 1)
|
||||
|| (cabi == FFI_FASTCALL && stack_args_count < 2))
|
||||
{
|
||||
if (z <= 4
|
||||
&& ((*p_arg)->type != FFI_TYPE_FLOAT
|
||||
&& (*p_arg)->type != FFI_TYPE_STRUCT))
|
||||
{
|
||||
p_stack_args[stack_args_count] = z;
|
||||
p_stack_data[stack_args_count] = argp;
|
||||
++stack_args_count;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p_argv++;
|
||||
#ifdef X86_WIN64
|
||||
argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
|
||||
#else
|
||||
argp += z;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef X86_WIN32
|
||||
/* We need to move the register-passed arguments for thiscall/fastcall
|
||||
on top of stack, so that those can be moved to registers ecx/edx by
|
||||
call-handler. */
|
||||
if (stack_args_count > 0)
|
||||
{
|
||||
size_t zz = (p_stack_args[0] + 3) & ~3;
|
||||
char *h;
|
||||
|
||||
/* Move first argument to top-stack position. */
|
||||
if (p_stack_data[0] != argp2)
|
||||
{
|
||||
h = alloca (zz + 1);
|
||||
memcpy (h, p_stack_data[0], zz);
|
||||
memmove (argp2 + zz, argp2,
|
||||
(size_t) ((char *) p_stack_data[0] - (char*)argp2));
|
||||
memcpy (argp2, h, zz);
|
||||
}
|
||||
|
||||
argp2 += zz;
|
||||
--stack_args_count;
|
||||
if (zz > 4)
|
||||
stack_args_count = 0;
|
||||
|
||||
/* If we have a second argument, then move it on top
|
||||
after the first one. */
|
||||
if (stack_args_count > 0 && p_stack_data[1] != argp2)
|
||||
{
|
||||
zz = p_stack_args[1];
|
||||
zz = (zz + 3) & ~3;
|
||||
h = alloca (zz + 1);
|
||||
h = alloca (zz + 1);
|
||||
memcpy (h, p_stack_data[1], zz);
|
||||
memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2));
|
||||
memcpy (argp2, h, zz);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perform machine dependent cif processing */
|
||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
{
|
||||
unsigned int i;
|
||||
ffi_type **ptr;
|
||||
|
||||
/* Set the return type flag */
|
||||
switch (cif->rtype->type)
|
||||
{
|
||||
case FFI_TYPE_VOID:
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_UINT16:
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
#ifdef X86_WIN64
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_SINT32:
|
||||
#endif
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_DOUBLE:
|
||||
#ifndef X86_WIN64
|
||||
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
#endif
|
||||
#endif
|
||||
cif->flags = (unsigned) cif->rtype->type;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT64:
|
||||
#ifdef X86_WIN64
|
||||
case FFI_TYPE_POINTER:
|
||||
#endif
|
||||
cif->flags = FFI_TYPE_SINT64;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
#ifndef X86
|
||||
if (cif->rtype->size == 1)
|
||||
{
|
||||
cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
|
||||
}
|
||||
else if (cif->rtype->size == 2)
|
||||
{
|
||||
cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
|
||||
}
|
||||
else if (cif->rtype->size == 4)
|
||||
{
|
||||
#ifdef X86_WIN64
|
||||
cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
|
||||
#else
|
||||
cif->flags = FFI_TYPE_INT; /* same as int type */
|
||||
#endif
|
||||
}
|
||||
else if (cif->rtype->size == 8)
|
||||
{
|
||||
cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef X86_WIN32
|
||||
if (cif->abi == FFI_MS_CDECL)
|
||||
cif->flags = FFI_TYPE_MS_STRUCT;
|
||||
else
|
||||
#endif
|
||||
cif->flags = FFI_TYPE_STRUCT;
|
||||
/* allocate space for return value pointer */
|
||||
cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef X86_WIN64
|
||||
cif->flags = FFI_TYPE_SINT64;
|
||||
break;
|
||||
case FFI_TYPE_INT:
|
||||
cif->flags = FFI_TYPE_SINT32;
|
||||
#else
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
|
||||
{
|
||||
if (((*ptr)->alignment - 1) & cif->bytes)
|
||||
cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
|
||||
cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
|
||||
}
|
||||
|
||||
#ifdef X86_WIN64
|
||||
/* ensure space for storing four registers */
|
||||
cif->bytes += 4 * sizeof(ffi_arg);
|
||||
#endif
|
||||
|
||||
#ifdef X86_DARWIN
|
||||
cif->bytes = (cif->bytes + 15) & ~0xF;
|
||||
#endif
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
#ifdef X86_WIN64
|
||||
extern int
|
||||
ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
|
||||
unsigned, unsigned, unsigned *, void (*fn)(void));
|
||||
#elif defined(X86_WIN32)
|
||||
extern void
|
||||
ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
|
||||
unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
|
||||
#else
|
||||
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
|
||||
unsigned, unsigned, unsigned *, void (*fn)(void));
|
||||
#endif
|
||||
|
||||
void ffi_call(ffi_cif *cif, void (*fn)(void), 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 */
|
||||
|
||||
#ifdef X86_WIN64
|
||||
if (rvalue == NULL
|
||||
&& cif->flags == FFI_TYPE_STRUCT
|
||||
&& cif->rtype->size != 1 && cif->rtype->size != 2
|
||||
&& cif->rtype->size != 4 && cif->rtype->size != 8)
|
||||
{
|
||||
ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
|
||||
}
|
||||
#else
|
||||
if (rvalue == NULL
|
||||
&& (cif->flags == FFI_TYPE_STRUCT
|
||||
|| cif->flags == FFI_TYPE_MS_STRUCT))
|
||||
{
|
||||
ecif.rvalue = alloca(cif->rtype->size);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ecif.rvalue = rvalue;
|
||||
|
||||
|
||||
switch (cif->abi)
|
||||
{
|
||||
#ifdef X86_WIN64
|
||||
case FFI_WIN64:
|
||||
ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
|
||||
cif->flags, ecif.rvalue, fn);
|
||||
break;
|
||||
#elif defined(X86_WIN32)
|
||||
case FFI_SYSV:
|
||||
case FFI_STDCALL:
|
||||
case FFI_MS_CDECL:
|
||||
ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
|
||||
ecif.rvalue, fn);
|
||||
break;
|
||||
case FFI_THISCALL:
|
||||
case FFI_FASTCALL:
|
||||
{
|
||||
unsigned int abi = cif->abi;
|
||||
unsigned int i, passed_regs = 0;
|
||||
|
||||
if (cif->flags == FFI_TYPE_STRUCT)
|
||||
++passed_regs;
|
||||
|
||||
for (i=0; i < cif->nargs && passed_regs < 2;i++)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
|
||||
|| cif->arg_types[i]->type == FFI_TYPE_STRUCT)
|
||||
continue;
|
||||
sz = (cif->arg_types[i]->size + 3) & ~3;
|
||||
if (sz == 0 || sz > 4)
|
||||
continue;
|
||||
++passed_regs;
|
||||
}
|
||||
if (passed_regs < 2 && abi == FFI_FASTCALL)
|
||||
abi = FFI_THISCALL;
|
||||
if (passed_regs < 1 && abi == FFI_THISCALL)
|
||||
abi = FFI_STDCALL;
|
||||
ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags,
|
||||
ecif.rvalue, fn);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case FFI_SYSV:
|
||||
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
|
||||
fn);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** private members **/
|
||||
|
||||
/* The following __attribute__((regparm(1))) decorations will have no effect
|
||||
on MSVC - standard cdecl convention applies. */
|
||||
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
|
||||
void** args, ffi_cif* cif);
|
||||
void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
|
||||
__attribute__ ((regparm(1)));
|
||||
unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
|
||||
__attribute__ ((regparm(1)));
|
||||
void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
|
||||
__attribute__ ((regparm(1)));
|
||||
#ifdef X86_WIN32
|
||||
void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
|
||||
__attribute__ ((regparm(1)));
|
||||
void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
|
||||
__attribute__ ((regparm(1)));
|
||||
void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *)
|
||||
__attribute__ ((regparm(1)));
|
||||
#endif
|
||||
#ifdef X86_WIN64
|
||||
void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
|
||||
#endif
|
||||
|
||||
/* This function is jumped to by the trampoline */
|
||||
|
||||
#ifdef X86_WIN64
|
||||
void * FFI_HIDDEN
|
||||
ffi_closure_win64_inner (ffi_closure *closure, void *args) {
|
||||
ffi_cif *cif;
|
||||
void **arg_area;
|
||||
void *result;
|
||||
void *resp = &result;
|
||||
|
||||
cif = closure->cif;
|
||||
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
||||
|
||||
/* this call will initialize ARG_AREA, such that each
|
||||
* element in that array points to the corresponding
|
||||
* value on the stack; and if the function returns
|
||||
* a structure, it will change RESP to point to the
|
||||
* structure return address. */
|
||||
|
||||
ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
|
||||
|
||||
(closure->fun) (cif, resp, arg_area, closure->user_data);
|
||||
|
||||
/* The result is returned in rax. This does the right thing for
|
||||
result types except for floats; we have to 'mov xmm0, rax' in the
|
||||
caller to correct this.
|
||||
TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
|
||||
*/
|
||||
return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
|
||||
}
|
||||
|
||||
#else
|
||||
unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
|
||||
ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
|
||||
{
|
||||
/* our various things... */
|
||||
ffi_cif *cif;
|
||||
void **arg_area;
|
||||
|
||||
cif = closure->cif;
|
||||
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
||||
|
||||
/* this call will initialize ARG_AREA, such that each
|
||||
* element in that array points to the corresponding
|
||||
* value on the stack; and if the function returns
|
||||
* a structure, it will change RESP to point to the
|
||||
* structure return address. */
|
||||
|
||||
ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
|
||||
|
||||
(closure->fun) (cif, *respp, arg_area, closure->user_data);
|
||||
|
||||
return cif->flags;
|
||||
}
|
||||
#endif /* !X86_WIN64 */
|
||||
|
||||
static void
|
||||
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
|
||||
ffi_cif *cif)
|
||||
{
|
||||
register unsigned int i;
|
||||
register void **p_argv;
|
||||
register char *argp;
|
||||
register ffi_type **p_arg;
|
||||
|
||||
argp = stack;
|
||||
|
||||
#ifdef X86_WIN64
|
||||
if (cif->rtype->size > sizeof(ffi_arg)
|
||||
|| (cif->flags == FFI_TYPE_STRUCT
|
||||
&& (cif->rtype->size != 1 && cif->rtype->size != 2
|
||||
&& cif->rtype->size != 4 && cif->rtype->size != 8))) {
|
||||
*rvalue = *(void **) argp;
|
||||
argp += sizeof(void *);
|
||||
}
|
||||
#else
|
||||
if ( cif->flags == FFI_TYPE_STRUCT
|
||||
|| cif->flags == FFI_TYPE_MS_STRUCT ) {
|
||||
*rvalue = *(void **) argp;
|
||||
argp += sizeof(void *);
|
||||
}
|
||||
#endif
|
||||
|
||||
p_argv = avalue;
|
||||
|
||||
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
|
||||
{
|
||||
size_t z;
|
||||
|
||||
/* Align if necessary */
|
||||
if ((sizeof(void*) - 1) & (size_t) argp) {
|
||||
argp = (char *) ALIGN(argp, sizeof(void*));
|
||||
}
|
||||
|
||||
#ifdef X86_WIN64
|
||||
if ((*p_arg)->size > sizeof(ffi_arg)
|
||||
|| ((*p_arg)->type == FFI_TYPE_STRUCT
|
||||
&& ((*p_arg)->size != 1 && (*p_arg)->size != 2
|
||||
&& (*p_arg)->size != 4 && (*p_arg)->size != 8)))
|
||||
{
|
||||
z = sizeof(void *);
|
||||
*p_argv = *(void **)argp;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
z = (*p_arg)->size;
|
||||
|
||||
/* because we're little endian, this is what it turns into. */
|
||||
|
||||
*p_argv = (void*) argp;
|
||||
}
|
||||
|
||||
p_argv++;
|
||||
#ifdef X86_WIN64
|
||||
argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
|
||||
#else
|
||||
argp += z;
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
|
||||
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
|
||||
void* __fun = (void*)(FUN); \
|
||||
void* __ctx = (void*)(CTX); \
|
||||
*(unsigned char*) &__tramp[0] = 0x41; \
|
||||
*(unsigned char*) &__tramp[1] = 0xbb; \
|
||||
*(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
|
||||
*(unsigned char*) &__tramp[6] = 0x48; \
|
||||
*(unsigned char*) &__tramp[7] = 0xb8; \
|
||||
*(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
|
||||
*(unsigned char *) &__tramp[16] = 0x49; \
|
||||
*(unsigned char *) &__tramp[17] = 0xba; \
|
||||
*(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
|
||||
*(unsigned char *) &__tramp[26] = 0x41; \
|
||||
*(unsigned char *) &__tramp[27] = 0xff; \
|
||||
*(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \
|
||||
}
|
||||
|
||||
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
|
||||
|
||||
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
|
||||
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
|
||||
unsigned int __fun = (unsigned int)(FUN); \
|
||||
unsigned int __ctx = (unsigned int)(CTX); \
|
||||
unsigned int __dis = __fun - (__ctx + 10); \
|
||||
*(unsigned char*) &__tramp[0] = 0xb8; \
|
||||
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
|
||||
*(unsigned char *) &__tramp[5] = 0xe9; \
|
||||
*(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
|
||||
}
|
||||
|
||||
#define FFI_INIT_TRAMPOLINE_THISCALL(TRAMP,FUN,CTX,SIZE) \
|
||||
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
|
||||
unsigned int __fun = (unsigned int)(FUN); \
|
||||
unsigned int __ctx = (unsigned int)(CTX); \
|
||||
unsigned int __dis = __fun - (__ctx + 49); \
|
||||
unsigned short __size = (unsigned short)(SIZE); \
|
||||
*(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \
|
||||
*(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \
|
||||
*(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \
|
||||
*(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \
|
||||
*(unsigned char*) &__tramp[13] = 0xb8; \
|
||||
*(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \
|
||||
*(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \
|
||||
*(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \
|
||||
*(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \
|
||||
*(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \
|
||||
*(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \
|
||||
*(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \
|
||||
*(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \
|
||||
*(unsigned char*) &__tramp[39] = 0xb8; \
|
||||
*(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \
|
||||
*(unsigned char *) &__tramp[44] = 0xe8; \
|
||||
*(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \
|
||||
*(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \
|
||||
*(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \
|
||||
}
|
||||
|
||||
#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \
|
||||
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
|
||||
unsigned int __fun = (unsigned int)(FUN); \
|
||||
unsigned int __ctx = (unsigned int)(CTX); \
|
||||
unsigned int __dis = __fun - (__ctx + 10); \
|
||||
unsigned short __size = (unsigned short)(SIZE); \
|
||||
*(unsigned char*) &__tramp[0] = 0xb8; \
|
||||
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
|
||||
*(unsigned char *) &__tramp[5] = 0xe8; \
|
||||
*(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \
|
||||
*(unsigned char *) &__tramp[10] = 0xc2; \
|
||||
*(unsigned short*) &__tramp[11] = __size; /* ret __size */ \
|
||||
}
|
||||
|
||||
/* the cif must already be prep'ed */
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
#ifdef X86_WIN64
|
||||
#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
|
||||
#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
|
||||
if (cif->abi == FFI_WIN64)
|
||||
{
|
||||
int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
|
||||
FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
|
||||
&ffi_closure_win64,
|
||||
codeloc, mask);
|
||||
/* make sure we can execute here */
|
||||
}
|
||||
#else
|
||||
if (cif->abi == FFI_SYSV)
|
||||
{
|
||||
FFI_INIT_TRAMPOLINE (&closure->tramp[0],
|
||||
&ffi_closure_SYSV,
|
||||
(void*)codeloc);
|
||||
}
|
||||
#ifdef X86_WIN32
|
||||
else if (cif->abi == FFI_THISCALL)
|
||||
{
|
||||
FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0],
|
||||
&ffi_closure_THISCALL,
|
||||
(void*)codeloc,
|
||||
cif->bytes);
|
||||
}
|
||||
else if (cif->abi == FFI_STDCALL)
|
||||
{
|
||||
FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
|
||||
&ffi_closure_STDCALL,
|
||||
(void*)codeloc, cif->bytes);
|
||||
}
|
||||
else if (cif->abi == FFI_MS_CDECL)
|
||||
{
|
||||
FFI_INIT_TRAMPOLINE (&closure->tramp[0],
|
||||
&ffi_closure_SYSV,
|
||||
(void*)codeloc);
|
||||
}
|
||||
#endif /* X86_WIN32 */
|
||||
#endif /* !X86_WIN64 */
|
||||
else
|
||||
{
|
||||
return FFI_BAD_ABI;
|
||||
}
|
||||
|
||||
closure->cif = cif;
|
||||
closure->user_data = user_data;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
/* ------- Native raw API support -------------------------------- */
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
||||
ffi_status
|
||||
ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cif->abi != FFI_SYSV) {
|
||||
#ifdef X86_WIN32
|
||||
if (cif->abi != FFI_THISCALL)
|
||||
#endif
|
||||
return FFI_BAD_ABI;
|
||||
}
|
||||
|
||||
/* we currently don't support certain kinds of arguments for raw
|
||||
closures. This should be implemented by a separate assembly
|
||||
language routine, since it would require argument processing,
|
||||
something we don't do now for performance. */
|
||||
|
||||
for (i = cif->nargs-1; i >= 0; i--)
|
||||
{
|
||||
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
|
||||
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
|
||||
}
|
||||
|
||||
#ifdef X86_WIN32
|
||||
if (cif->abi == FFI_SYSV)
|
||||
{
|
||||
#endif
|
||||
FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
|
||||
codeloc);
|
||||
#ifdef X86_WIN32
|
||||
}
|
||||
else if (cif->abi == FFI_THISCALL)
|
||||
{
|
||||
FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL,
|
||||
codeloc, cif->bytes);
|
||||
}
|
||||
#endif
|
||||
closure->cif = cif;
|
||||
closure->user_data = user_data;
|
||||
closure->fun = fun;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
ffi_prep_args_raw(char *stack, extended_cif *ecif)
|
||||
{
|
||||
memcpy (stack, ecif->avalue, ecif->cif->bytes);
|
||||
}
|
||||
|
||||
/* we borrow this routine from libffi (it must be changed, though, to
|
||||
* actually call the function passed in the first argument. as of
|
||||
* libffi-1.20, this is not the case.)
|
||||
*/
|
||||
|
||||
void
|
||||
ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
|
||||
{
|
||||
extended_cif ecif;
|
||||
void **avalue = (void **)fake_avalue;
|
||||
|
||||
ecif.cif = cif;
|
||||
ecif.avalue = avalue;
|
||||
|
||||
/* If the return value is a struct and we don't have a return */
|
||||
/* value address then we need to make one */
|
||||
|
||||
if (rvalue == NULL
|
||||
&& (cif->flags == FFI_TYPE_STRUCT
|
||||
|| cif->flags == FFI_TYPE_MS_STRUCT))
|
||||
{
|
||||
ecif.rvalue = alloca(cif->rtype->size);
|
||||
}
|
||||
else
|
||||
ecif.rvalue = rvalue;
|
||||
|
||||
|
||||
switch (cif->abi)
|
||||
{
|
||||
#ifdef X86_WIN32
|
||||
case FFI_SYSV:
|
||||
case FFI_STDCALL:
|
||||
case FFI_MS_CDECL:
|
||||
ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
|
||||
ecif.rvalue, fn);
|
||||
break;
|
||||
case FFI_THISCALL:
|
||||
case FFI_FASTCALL:
|
||||
{
|
||||
unsigned int abi = cif->abi;
|
||||
unsigned int i, passed_regs = 0;
|
||||
|
||||
if (cif->flags == FFI_TYPE_STRUCT)
|
||||
++passed_regs;
|
||||
|
||||
for (i=0; i < cif->nargs && passed_regs < 2;i++)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
|
||||
|| cif->arg_types[i]->type == FFI_TYPE_STRUCT)
|
||||
continue;
|
||||
sz = (cif->arg_types[i]->size + 3) & ~3;
|
||||
if (sz == 0 || sz > 4)
|
||||
continue;
|
||||
++passed_regs;
|
||||
}
|
||||
if (passed_regs < 2 && abi == FFI_FASTCALL)
|
||||
cif->abi = abi = FFI_THISCALL;
|
||||
if (passed_regs < 1 && abi == FFI_THISCALL)
|
||||
cif->abi = abi = FFI_STDCALL;
|
||||
ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags,
|
||||
ecif.rvalue, fn);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case FFI_SYSV:
|
||||
ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
|
||||
ecif.rvalue, fn);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !__x86_64__ || X86_WIN64 */
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
|
||||
ffi.c - Copyright (c) 2017 Anthony Green
|
||||
Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
|
||||
Copyright (c) 2002 Ranjit Mathew
|
||||
Copyright (c) 2002 Bo Thorsen
|
||||
Copyright (c) 2002 Roger Sayle
|
||||
|
@ -28,10 +29,12 @@
|
|||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __x86_64__
|
||||
#if defined(__i386__) || defined(_M_IX86)
|
||||
#include <ffi.h>
|
||||
#include <ffi_common.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <tramp.h>
|
||||
#include "internal.h"
|
||||
|
||||
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
|
||||
|
@ -49,6 +52,13 @@
|
|||
# define __declspec(x) __attribute__((x))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
/* Stack is not 16-byte aligned on Windows. */
|
||||
#define STACK_ALIGN(bytes) (bytes)
|
||||
#else
|
||||
#define STACK_ALIGN(bytes) FFI_ALIGN (bytes, 16)
|
||||
#endif
|
||||
|
||||
/* Perform machine dependent cif processing. */
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
|
@ -134,7 +144,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
break;
|
||||
}
|
||||
/* Allocate space for return value pointer. */
|
||||
bytes += ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
|
||||
bytes += FFI_ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
|
||||
}
|
||||
break;
|
||||
case FFI_TYPE_COMPLEX:
|
||||
|
@ -172,10 +182,10 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
{
|
||||
ffi_type *t = cif->arg_types[i];
|
||||
|
||||
bytes = ALIGN (bytes, t->alignment);
|
||||
bytes += ALIGN (t->size, FFI_SIZEOF_ARG);
|
||||
bytes = FFI_ALIGN (bytes, t->alignment);
|
||||
bytes += FFI_ALIGN (t->size, FFI_SIZEOF_ARG);
|
||||
}
|
||||
cif->bytes = ALIGN (bytes, 16);
|
||||
cif->bytes = bytes;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
@ -234,12 +244,25 @@ static const struct abi_params abi_params[FFI_LAST_ABI] = {
|
|||
[FFI_MS_CDECL] = { 1, R_ECX, 0 }
|
||||
};
|
||||
|
||||
extern void ffi_call_i386(struct call_frame *, char *)
|
||||
#if HAVE_FASTCALL
|
||||
__declspec(fastcall)
|
||||
#ifdef HAVE_FASTCALL
|
||||
#ifdef _MSC_VER
|
||||
#define FFI_DECLARE_FASTCALL __fastcall
|
||||
#else
|
||||
#define FFI_DECLARE_FASTCALL __declspec(fastcall)
|
||||
#endif
|
||||
#else
|
||||
#define FFI_DECLARE_FASTCALL
|
||||
#endif
|
||||
FFI_HIDDEN;
|
||||
|
||||
extern void FFI_DECLARE_FASTCALL ffi_call_i386(struct call_frame *, char *) FFI_HIDDEN;
|
||||
|
||||
/* We perform some black magic here to use some of the parent's stack frame in
|
||||
* ffi_call_i386() that breaks with the MSVC compiler with the /RTCs or /GZ
|
||||
* flags. Disable the 'Stack frame run time error checking' for this function
|
||||
* so we don't hit weird exceptions in debug builds. */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma runtime_checks("s", off)
|
||||
#endif
|
||||
static void
|
||||
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
|
@ -277,7 +300,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
}
|
||||
}
|
||||
|
||||
bytes = cif->bytes;
|
||||
bytes = STACK_ALIGN (cif->bytes);
|
||||
stack = alloca(bytes + sizeof(*frame) + rsize);
|
||||
argp = (dir < 0 ? stack + bytes : stack);
|
||||
frame = (struct call_frame *)(stack + bytes);
|
||||
|
@ -334,9 +357,18 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
}
|
||||
else
|
||||
{
|
||||
size_t za = ALIGN (z, FFI_SIZEOF_ARG);
|
||||
size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
|
||||
size_t align = FFI_SIZEOF_ARG;
|
||||
|
||||
/* Issue 434: For thiscall and fastcall, if the paramter passed
|
||||
as 64-bit integer or struct, all following integer parameters
|
||||
will be passed on stack. */
|
||||
if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
|
||||
&& (t == FFI_TYPE_SINT64
|
||||
|| t == FFI_TYPE_UINT64
|
||||
|| t == FFI_TYPE_STRUCT))
|
||||
narg_reg = 2;
|
||||
|
||||
/* Alignment rules for arguments are quite complex. Vectors and
|
||||
structures with 16 byte alignment get it. Note that long double
|
||||
on Darwin does have 16 byte alignment, and does not get this
|
||||
|
@ -356,7 +388,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
}
|
||||
else
|
||||
{
|
||||
argp = (char *)ALIGN (argp, align);
|
||||
argp = (char *)FFI_ALIGN (argp, align);
|
||||
memcpy (argp, valp, z);
|
||||
argp += za;
|
||||
}
|
||||
|
@ -366,6 +398,9 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
|
||||
ffi_call_i386 (frame, stack);
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma runtime_checks("s", restore)
|
||||
#endif
|
||||
|
||||
void
|
||||
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
|
@ -373,18 +408,25 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
|||
ffi_call_int (cif, fn, rvalue, avalue, NULL);
|
||||
}
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
ffi_call_int (cif, fn, rvalue, avalue, closure);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** private members **/
|
||||
|
||||
void FFI_HIDDEN ffi_closure_i386(void);
|
||||
void FFI_HIDDEN ffi_closure_STDCALL(void);
|
||||
void FFI_HIDDEN ffi_closure_REGISTER(void);
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
void FFI_HIDDEN ffi_closure_i386_alt(void);
|
||||
void FFI_HIDDEN ffi_closure_STDCALL_alt(void);
|
||||
void FFI_HIDDEN ffi_closure_REGISTER_alt(void);
|
||||
#endif
|
||||
|
||||
struct closure_frame
|
||||
{
|
||||
|
@ -395,10 +437,7 @@ struct closure_frame
|
|||
void *user_data; /* 36 */
|
||||
};
|
||||
|
||||
int FFI_HIDDEN
|
||||
#if HAVE_FASTCALL
|
||||
__declspec(fastcall)
|
||||
#endif
|
||||
int FFI_HIDDEN FFI_DECLARE_FASTCALL
|
||||
ffi_closure_inner (struct closure_frame *frame, char *stack)
|
||||
{
|
||||
ffi_cif *cif = frame->cif;
|
||||
|
@ -415,7 +454,7 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
|
|||
rvalue = frame->rettemp;
|
||||
pabi = &abi_params[cabi];
|
||||
dir = pabi->dir;
|
||||
argp = (dir < 0 ? stack + cif->bytes : stack);
|
||||
argp = (dir < 0 ? stack + STACK_ALIGN (cif->bytes) : stack);
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
|
@ -463,13 +502,22 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
|
|||
}
|
||||
else
|
||||
{
|
||||
size_t za = ALIGN (z, FFI_SIZEOF_ARG);
|
||||
size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
|
||||
size_t align = FFI_SIZEOF_ARG;
|
||||
|
||||
/* See the comment in ffi_call_int. */
|
||||
if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
|
||||
align = 16;
|
||||
|
||||
/* Issue 434: For thiscall and fastcall, if the paramter passed
|
||||
as 64-bit integer or struct, all following integer parameters
|
||||
will be passed on stack. */
|
||||
if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
|
||||
&& (t == FFI_TYPE_SINT64
|
||||
|| t == FFI_TYPE_UINT64
|
||||
|| t == FFI_TYPE_STRUCT))
|
||||
narg_reg = 2;
|
||||
|
||||
if (dir < 0)
|
||||
{
|
||||
/* ??? These reverse argument ABIs are probably too old
|
||||
|
@ -479,7 +527,7 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
|
|||
}
|
||||
else
|
||||
{
|
||||
argp = (char *)ALIGN (argp, align);
|
||||
argp = (char *)FFI_ALIGN (argp, align);
|
||||
valp = argp;
|
||||
argp += za;
|
||||
}
|
||||
|
@ -490,10 +538,17 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
|
|||
|
||||
frame->fun (cif, rvalue, avalue, frame->user_data);
|
||||
|
||||
if (cabi == FFI_STDCALL)
|
||||
return flags + (cif->bytes << X86_RET_POP_SHIFT);
|
||||
else
|
||||
return flags;
|
||||
switch (cabi)
|
||||
{
|
||||
case FFI_STDCALL:
|
||||
return flags | (cif->bytes << X86_RET_POP_SHIFT);
|
||||
case FFI_THISCALL:
|
||||
case FFI_FASTCALL:
|
||||
return flags | ((cif->bytes - (narg_reg * FFI_SIZEOF_ARG))
|
||||
<< X86_RET_POP_SHIFT);
|
||||
default:
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
ffi_status
|
||||
|
@ -510,30 +565,51 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||
switch (cif->abi)
|
||||
{
|
||||
case FFI_SYSV:
|
||||
case FFI_THISCALL:
|
||||
case FFI_FASTCALL:
|
||||
case FFI_MS_CDECL:
|
||||
dest = ffi_closure_i386;
|
||||
break;
|
||||
case FFI_STDCALL:
|
||||
case FFI_THISCALL:
|
||||
case FFI_FASTCALL:
|
||||
case FFI_PASCAL:
|
||||
dest = ffi_closure_STDCALL;
|
||||
break;
|
||||
case FFI_REGISTER:
|
||||
dest = ffi_closure_REGISTER;
|
||||
op = 0x68; /* pushl imm */
|
||||
break;
|
||||
default:
|
||||
return FFI_BAD_ABI;
|
||||
}
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
if (ffi_tramp_is_present(closure))
|
||||
{
|
||||
/* Initialize the static trampoline's parameters. */
|
||||
if (dest == ffi_closure_i386)
|
||||
dest = ffi_closure_i386_alt;
|
||||
else if (dest == ffi_closure_STDCALL)
|
||||
dest = ffi_closure_STDCALL_alt;
|
||||
else
|
||||
dest = ffi_closure_REGISTER_alt;
|
||||
ffi_tramp_set_parms (closure->ftramp, dest, closure);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the dynamic trampoline. */
|
||||
/* endbr32. */
|
||||
*(UINT32 *) tramp = 0xfb1e0ff3;
|
||||
|
||||
/* movl or pushl immediate. */
|
||||
tramp[0] = op;
|
||||
*(void **)(tramp + 1) = codeloc;
|
||||
tramp[4] = op;
|
||||
*(void **)(tramp + 5) = codeloc;
|
||||
|
||||
/* jmp dest */
|
||||
tramp[5] = 0xe9;
|
||||
*(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10);
|
||||
tramp[9] = 0xe9;
|
||||
*(unsigned *)(tramp + 10) = (unsigned)dest - ((unsigned)codeloc + 14);
|
||||
|
||||
out:
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
closure->user_data = user_data;
|
||||
|
@ -541,6 +617,8 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
|
||||
void FFI_HIDDEN ffi_go_closure_EAX(void);
|
||||
void FFI_HIDDEN ffi_go_closure_ECX(void);
|
||||
void FFI_HIDDEN ffi_go_closure_STDCALL(void);
|
||||
|
@ -577,6 +655,8 @@ ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
|
||||
/* ------- Native raw API support -------------------------------- */
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
@ -669,8 +749,9 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
|
|||
}
|
||||
}
|
||||
|
||||
bytes = cif->bytes;
|
||||
argp = stack = alloca(bytes + sizeof(*frame) + rsize);
|
||||
bytes = STACK_ALIGN (cif->bytes);
|
||||
argp = stack =
|
||||
(void *)((uintptr_t)alloca(bytes + sizeof(*frame) + rsize + 15) & ~16);
|
||||
frame = (struct call_frame *)(stack + bytes);
|
||||
if (rsize)
|
||||
rvalue = frame + 1;
|
||||
|
@ -714,7 +795,7 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
|
|||
else
|
||||
{
|
||||
memcpy (argp, avalue, z);
|
||||
z = ALIGN (z, FFI_SIZEOF_ARG);
|
||||
z = FFI_ALIGN (z, FFI_SIZEOF_ARG);
|
||||
argp += z;
|
||||
}
|
||||
avalue += z;
|
||||
|
@ -726,4 +807,17 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
|
|||
ffi_call_i386 (frame, stack);
|
||||
}
|
||||
#endif /* !FFI_NO_RAW_API */
|
||||
#endif /* !__x86_64__ */
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
void *
|
||||
ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
|
||||
{
|
||||
extern void *trampoline_code_table;
|
||||
|
||||
*map_size = X86_TRAMP_MAP_SIZE;
|
||||
*tramp_size = X86_TRAMP_SIZE;
|
||||
return &trampoline_code_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
ffi64.c - Copyright (c) 2013 The Written Word, Inc.
|
||||
Copyright (c) 2011 Anthony Green
|
||||
ffi64.c - Copyright (c) 2011, 2018 Anthony Green
|
||||
Copyright (c) 2013 The Written Word, Inc.
|
||||
Copyright (c) 2008, 2010 Red Hat, Inc.
|
||||
Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de>
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <tramp.h>
|
||||
#include "internal64.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
@ -217,10 +218,10 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
|||
case FFI_TYPE_STRUCT:
|
||||
{
|
||||
const size_t UNITS_PER_WORD = 8;
|
||||
size_t words = (type->size + byte_offset + UNITS_PER_WORD - 1)
|
||||
/ UNITS_PER_WORD;
|
||||
size_t words = (type->size + byte_offset + UNITS_PER_WORD - 1)
|
||||
/ UNITS_PER_WORD;
|
||||
ffi_type **ptr;
|
||||
int i;
|
||||
unsigned int i;
|
||||
enum x86_64_reg_class subclasses[MAX_CLASSES];
|
||||
|
||||
/* If the struct is larger than 32 bytes, pass it on the stack. */
|
||||
|
@ -244,14 +245,15 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
|||
{
|
||||
size_t num, pos;
|
||||
|
||||
byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
|
||||
byte_offset = FFI_ALIGN (byte_offset, (*ptr)->alignment);
|
||||
|
||||
num = classify_argument (*ptr, subclasses, byte_offset % 8);
|
||||
if (num == 0)
|
||||
return 0;
|
||||
pos = byte_offset / 8;
|
||||
for (i = 0; i < num && (i + pos) < words; i++)
|
||||
pos = byte_offset / 8;
|
||||
for (i = 0; i < num && (i + pos) < words; i++)
|
||||
{
|
||||
size_t pos = byte_offset / 8;
|
||||
classes[i + pos] =
|
||||
merge_classes (subclasses[i], classes[i + pos]);
|
||||
}
|
||||
|
@ -283,7 +285,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
|||
|
||||
/* The X86_64_SSEUP_CLASS should be always preceded by
|
||||
X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
|
||||
if (classes[i] == X86_64_SSEUP_CLASS
|
||||
if (i > 1 && classes[i] == X86_64_SSEUP_CLASS
|
||||
&& classes[i - 1] != X86_64_SSE_CLASS
|
||||
&& classes[i - 1] != X86_64_SSEUP_CLASS)
|
||||
{
|
||||
|
@ -294,7 +296,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
|
|||
|
||||
/* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
|
||||
everything should be passed in memory. */
|
||||
if (classes[i] == X86_64_X87UP_CLASS
|
||||
if (i > 1 && classes[i] == X86_64_X87UP_CLASS
|
||||
&& (classes[i - 1] != X86_64_X87_CLASS))
|
||||
{
|
||||
/* The first one should never be X86_64_X87UP_CLASS. */
|
||||
|
@ -351,7 +353,8 @@ examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
|
|||
_Bool in_return, int *pngpr, int *pnsse)
|
||||
{
|
||||
size_t n;
|
||||
int i, ngpr, nsse;
|
||||
unsigned int i;
|
||||
int ngpr, nsse;
|
||||
|
||||
n = classify_argument (type, classes, 0);
|
||||
if (n == 0)
|
||||
|
@ -389,14 +392,24 @@ examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
|
|||
|
||||
/* Perform machine dependent cif processing. */
|
||||
|
||||
ffi_status
|
||||
#ifndef __ILP32__
|
||||
extern ffi_status
|
||||
ffi_prep_cif_machdep_efi64(ffi_cif *cif);
|
||||
#endif
|
||||
|
||||
ffi_status FFI_HIDDEN
|
||||
ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
{
|
||||
int gprcount, ssecount, i, avn, ngpr, nsse, flags;
|
||||
int gprcount, ssecount, i, avn, ngpr, nsse;
|
||||
unsigned flags;
|
||||
enum x86_64_reg_class classes[MAX_CLASSES];
|
||||
size_t bytes, n, rtype_size;
|
||||
ffi_type *rtype;
|
||||
|
||||
#ifndef __ILP32__
|
||||
if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
|
||||
return ffi_prep_cif_machdep_efi64(cif);
|
||||
#endif
|
||||
if (cif->abi != FFI_UNIX64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
|
@ -441,9 +454,11 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
case FFI_TYPE_DOUBLE:
|
||||
flags = UNIX64_RET_XMM64;
|
||||
break;
|
||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||
case FFI_TYPE_LONGDOUBLE:
|
||||
flags = UNIX64_RET_X87;
|
||||
break;
|
||||
#endif
|
||||
case FFI_TYPE_STRUCT:
|
||||
n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
|
||||
if (n == 0)
|
||||
|
@ -489,7 +504,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT64:
|
||||
case FFI_TYPE_SINT64:
|
||||
flags = UNIX64_RET_ST_RAX_RDX | (rtype_size << UNIX64_SIZE_SHIFT);
|
||||
flags = UNIX64_RET_ST_RAX_RDX | ((unsigned) rtype_size << UNIX64_SIZE_SHIFT);
|
||||
break;
|
||||
case FFI_TYPE_FLOAT:
|
||||
flags = UNIX64_RET_XMM64;
|
||||
|
@ -524,7 +539,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
if (align < 8)
|
||||
align = 8;
|
||||
|
||||
bytes = ALIGN (bytes, align);
|
||||
bytes = FFI_ALIGN (bytes, align);
|
||||
bytes += cif->arg_types[i]->size;
|
||||
}
|
||||
else
|
||||
|
@ -537,7 +552,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
|||
flags |= UNIX64_FLAG_XMM_ARGS;
|
||||
|
||||
cif->flags = flags;
|
||||
cif->bytes = ALIGN (bytes, 8);
|
||||
cif->bytes = (unsigned) FFI_ALIGN (bytes, 8);
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
@ -599,7 +614,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
align = 8;
|
||||
|
||||
/* Pass this argument in memory. */
|
||||
argp = (void *) ALIGN (argp, align);
|
||||
argp = (void *) FFI_ALIGN (argp, align);
|
||||
memcpy (argp, avalue[i], size);
|
||||
argp += size;
|
||||
}
|
||||
|
@ -607,7 +622,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
{
|
||||
/* The argument is passed entirely in registers. */
|
||||
char *a = (char *) avalue[i];
|
||||
int j;
|
||||
unsigned int j;
|
||||
|
||||
for (j = 0; j < n; j++, a += 8, size -= 8)
|
||||
{
|
||||
|
@ -641,10 +656,10 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
break;
|
||||
case X86_64_SSE_CLASS:
|
||||
case X86_64_SSEDF_CLASS:
|
||||
reg_args->sse[ssecount++].i64 = *(UINT64 *) a;
|
||||
memcpy (®_args->sse[ssecount++].i64, a, sizeof(UINT64));
|
||||
break;
|
||||
case X86_64_SSESF_CLASS:
|
||||
reg_args->sse[ssecount++].i32 = *(UINT32 *) a;
|
||||
memcpy (®_args->sse[ssecount++].i32, a, sizeof(UINT32));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
|
@ -658,21 +673,63 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
|||
flags, rvalue, fn);
|
||||
}
|
||||
|
||||
#ifndef __ILP32__
|
||||
extern void
|
||||
ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
|
||||
#endif
|
||||
|
||||
void
|
||||
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
#ifndef __ILP32__
|
||||
if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
|
||||
{
|
||||
ffi_call_efi64(cif, fn, rvalue, avalue);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ffi_call_int (cif, fn, rvalue, avalue, NULL);
|
||||
}
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
|
||||
#ifndef __ILP32__
|
||||
extern void
|
||||
ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure);
|
||||
#endif
|
||||
|
||||
void
|
||||
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||
void **avalue, void *closure)
|
||||
{
|
||||
#ifndef __ILP32__
|
||||
if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
|
||||
{
|
||||
ffi_call_go_efi64(cif, fn, rvalue, avalue, closure);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ffi_call_int (cif, fn, rvalue, avalue, closure);
|
||||
}
|
||||
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
|
||||
extern void ffi_closure_unix64(void) FFI_HIDDEN;
|
||||
extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
extern void ffi_closure_unix64_alt(void) FFI_HIDDEN;
|
||||
extern void ffi_closure_unix64_sse_alt(void) FFI_HIDDEN;
|
||||
#endif
|
||||
|
||||
#ifndef __ILP32__
|
||||
extern ffi_status
|
||||
ffi_prep_closure_loc_efi64(ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *codeloc);
|
||||
#endif
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
|
@ -681,17 +738,23 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
static const unsigned char trampoline[16] = {
|
||||
/* leaq -0x7(%rip),%r10 # 0x0 */
|
||||
0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
|
||||
/* jmpq *0x3(%rip) # 0x10 */
|
||||
0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
|
||||
/* nopl (%rax) */
|
||||
0x0f, 0x1f, 0x00
|
||||
static const unsigned char trampoline[24] = {
|
||||
/* endbr64 */
|
||||
0xf3, 0x0f, 0x1e, 0xfa,
|
||||
/* leaq -0xb(%rip),%r10 # 0x0 */
|
||||
0x4c, 0x8d, 0x15, 0xf5, 0xff, 0xff, 0xff,
|
||||
/* jmpq *0x7(%rip) # 0x18 */
|
||||
0xff, 0x25, 0x07, 0x00, 0x00, 0x00,
|
||||
/* nopl 0(%rax) */
|
||||
0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
void (*dest)(void);
|
||||
char *tramp = closure->tramp;
|
||||
|
||||
#ifndef __ILP32__
|
||||
if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
|
||||
return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc);
|
||||
#endif
|
||||
if (cif->abi != FFI_UNIX64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
|
@ -700,9 +763,24 @@ ffi_prep_closure_loc (ffi_closure* closure,
|
|||
else
|
||||
dest = ffi_closure_unix64;
|
||||
|
||||
memcpy (tramp, trampoline, sizeof(trampoline));
|
||||
*(UINT64 *)(tramp + 16) = (uintptr_t)dest;
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
if (ffi_tramp_is_present(closure))
|
||||
{
|
||||
/* Initialize the static trampoline's parameters. */
|
||||
if (dest == ffi_closure_unix64_sse)
|
||||
dest = ffi_closure_unix64_sse_alt;
|
||||
else
|
||||
dest = ffi_closure_unix64_alt;
|
||||
ffi_tramp_set_parms (closure->ftramp, dest, closure);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the dynamic trampoline. */
|
||||
memcpy (tramp, trampoline, sizeof(trampoline));
|
||||
*(UINT64 *)(tramp + sizeof (trampoline)) = (uintptr_t)dest;
|
||||
|
||||
out:
|
||||
closure->cif = cif;
|
||||
closure->fun = fun;
|
||||
closure->user_data = user_data;
|
||||
|
@ -757,7 +835,7 @@ ffi_closure_unix64_inner(ffi_cif *cif,
|
|||
align = 8;
|
||||
|
||||
/* Pass this argument in memory. */
|
||||
argp = (void *) ALIGN (argp, align);
|
||||
argp = (void *) FFI_ALIGN (argp, align);
|
||||
avalue[i] = argp;
|
||||
argp += arg_types[i]->size;
|
||||
}
|
||||
|
@ -783,7 +861,7 @@ ffi_closure_unix64_inner(ffi_cif *cif,
|
|||
else
|
||||
{
|
||||
char *a = alloca (16);
|
||||
int j;
|
||||
unsigned int j;
|
||||
|
||||
avalue[i] = a;
|
||||
for (j = 0; j < n; j++, a += 8)
|
||||
|
@ -803,13 +881,25 @@ ffi_closure_unix64_inner(ffi_cif *cif,
|
|||
return flags;
|
||||
}
|
||||
|
||||
#ifdef FFI_GO_CLOSURES
|
||||
|
||||
extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
|
||||
extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
|
||||
|
||||
#ifndef __ILP32__
|
||||
extern ffi_status
|
||||
ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*));
|
||||
#endif
|
||||
|
||||
ffi_status
|
||||
ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*))
|
||||
{
|
||||
#ifndef __ILP32__
|
||||
if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
|
||||
return ffi_prep_go_closure_efi64(closure, cif, fun);
|
||||
#endif
|
||||
if (cif->abi != FFI_UNIX64)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
|
@ -822,4 +912,18 @@ ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
|
|||
return FFI_OK;
|
||||
}
|
||||
|
||||
#endif /* FFI_GO_CLOSURES */
|
||||
|
||||
#if defined(FFI_EXEC_STATIC_TRAMP)
|
||||
void *
|
||||
ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
|
||||
{
|
||||
extern void *trampoline_code_table;
|
||||
|
||||
*map_size = UNIX64_TRAMP_MAP_SIZE;
|
||||
*tramp_size = UNIX64_TRAMP_SIZE;
|
||||
return &trampoline_code_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue