Compare commits

...

29 Commits

Author SHA1 Message Date
Emil Taylor Bye
2263d6037f
Fix closures using FFI_REGISTER ABI (#949)
* Fix closures using FFI_REGISTER ABI

ffi_closure_REGISTER had the positions of the closure and return address
switched, resulting in a segfault when calling a closure created with
the FFI_REGISTER ABI.

* Fix comment and remove redundant assembly

* After fixing closures using FFI_REGISTER ABI, the comments were
  incorrect, not reflecting the value that was actually loaded into eax
  and ecx.
* Additionally, ecx was loaded with the data at esp + closure_FS only
  to write it back to esp + closure_FS. Both commands were removed as
  they end up not having any effect as ecx is overwritten during
  FFI_CLOSURE_COPY_TRAMP_DATA.
2025-12-26 10:04:51 -05:00
Jianfeng Liu
f067aef649
add CFLAGS -mcmodel=medium for loongarch64 (#945)
The default code model of gcc for loongarch64 platform provides
256MiB PC-relative addressing space[1], which is not enough for
linking large binaries like chromium. Setting it to medium can
let libffi_pic.a get linked to large binaries successfully.

[1] https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc#code_models
2025-12-18 15:38:42 -05:00
jonhermansen
3276df05a7
fix tsan tests on FreeBSD by linking to pthread (#944) 2025-11-05 18:28:02 -05:00
pietro
d6005499c2
Remove debugging output (#940)
Co-authored-by: Pietro Monteiro <pietro@sociotechnical.xyz>
2025-10-25 07:25:08 -04:00
ggardet
205fc530b0
aarch64: support GCS in assembly (#943)
Signed-off-by: Guillaume Gardet <guillaume.gardet@arm.com>
2025-10-25 07:24:40 -04:00
Martin Storsjö
2835f72cc7
arm: Fix compilation for Windows ARM targets (#936)
The .arch directive is only relevant for ELF targets, it is
unsupported for COFF and MachO targets.

Before 170bab47c90626a33cd08f2169034600cfd9589c, this was
not an issue as the directive was filtered out by the
ifndef __clang__.
2025-08-22 04:24:57 -04:00
Vyacheslav Chigrin
170bab47c9
Fix compilation for Cortex-A53 (#934)
When cross-compiling with clang and flags "--target=armv7-linux-gnueabihf -mcpu=cortex-a53"
compilation failed on instructions, used coprocessor.
2025-08-21 04:36:06 -04:00
Vyacheslav Chigrin
c3a2b65748
Fix test compilation for some Android platforms (#935) 2025-08-21 04:34:22 -04:00
Peter Bergner
c9b2a8a4ce
riscv: Add static trampoline support (#931) (#933)
Add static trampoline support to riscv32 and riscv64 Linux ABIs.
The implementation follows the s390x and powerpc implementations
which does not introduce a ffi_closure_*_alt function, but rather
jumps directly to the ffi_closure_asm function itself.
2025-08-07 13:40:35 +02:00
Anthony Green
e2eda0cf72 feat: Update libffi version to 3.5.2 with wasm64 and DragonFly BSD support 2025-08-02 08:56:01 +02:00
Anthony Green
b53b0042c2 Fix for systems without O_CLOEXEC 2025-08-02 08:52:25 +02:00
Kohei Tokunaga
20eacb22e9
Emscripten: Add wasm64 target (#927)
* src/wasm32: Allow building with Emscripten with 64bit support

MEMORY64 enables 64bit pointers so this commit updates the accessors for the
libffi data structures accordingly.

Each JS functions in ffi.c receives pointers as BigInt (i64) values and with
casts them to Numer (i53) using bigintToI53Checked. While memory64 supports
64bit addressing, the maximum memory size is currently limited to 16GiB
[1]. Therefore, we can assume that the passed pointers are within the
Number's range.

[1] https://webassembly.github.io/memory64/js-api/#limits

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>

* Add wasm64 target to the build scripts

This commit adds support for the wasm64 target via the configure
script. Emscripten supports two modes of the -sMEMORY64 flag[1] so the
script allows users specifying the value through a configuration variable.

Additionally, "src/wasm32" directory has been renamed to the more generic
"src/wasm" because it's now shared between both 32bit and 64bit builds.

[1] https://emscripten.org/docs/tools_reference/settings_reference.html#memory64

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>

* GitHub Actions: Add wasm64 tests

This commit adds a test matrix for wasm32, wasm64 and wasm64 with the
-sMEMORY64=2 flag, using the latest version of Emscripten. -Wno-main is
added to suppress the following warning in unwindtest.cc and
unwindtest_ffi_call.cc.

> FAIL: libffi.closures/unwindtest_ffi_call.cc -W -Wall -O2 (test for excess errors)
> Excess errors:
> ./libffi.closures/unwindtest_ffi_call.cc:20:5: warning: 'main' should not be 'extern "C"' [-Wmain]
>    20 | int main (void)
>       |     ^
> 1 warning generated.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>

* testsuite: Fix types of main function

test_libffi.py calls each test's main function without arguments, but some
tests define the main function with parameters. This signature mismatch
causes a runtime error with the recent version of Emscripten.

This commit resolves this issue by updating the function signatures to match
the way they are called.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>

* README: Add document about WASM64

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>

---------

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2025-08-02 02:28:46 -04:00
Weitian LI
b7885ace59
fix: enable FFI_MMAP_EXEC_WRIT for DragonFly BSD (#930)
Similar to PR #265 [1], we need to enable FFI_MMAP_EXEC_WRIT to use
explicit write+exec mapping on DragonFly BSD.

Without this fix, we were having segfaults with Meld [2]; it would crash
with SIGSEGV after 5 diff operations.  The crash was caused by it
attempting to execute code from non-execute memory region.  Moreover, if
we set the `machdep.pmap_nx_enable=2` tunable (i.e., strict NX mode),
Meld would crash upon the first diff operation.

Fix the `configure.ac` script to enable `FFI_MMAP_EXEC_WRIT` for
DragonFly BSD.  In addition, add it to the supported platforms table.

[1] https://github.com/libffi/libffi/pull/265
[2] https://meldmerge.org/
2025-08-02 02:27:51 -04:00
Anthony Green
6067118768 fix(tramp): ensure file descriptor is closed on exec. Thanks to Florian Weimer.
c# Please enter the commit message for your changes. Lines starting
2025-07-11 03:17:18 -04:00
Anthony Green
d0f831bca6 feat: add QUESTION to .gail-labels 2025-06-21 16:05:31 -04:00
Anthony Green
e28a0d5b07 ci: add fail-if-no-assets option in tarball workflow 2025-06-10 16:17:58 -04:00
Anthony Green
90220e51bc Update version. 2025-06-10 16:03:47 -04:00
Anthony Green
330467d55c Move new symbols to new symbol versioning. 2025-06-10 16:01:56 -04:00
Anthony Green
517310ddbf ci: update compiler versions in github workflow 2025-06-09 19:03:49 -04:00
Anthony Green
d994395ce7 ci: update gcc version to 15 in build process 2025-06-09 18:43:40 -04:00
Anthony Green
26d7be77cc ci: update build.sh for Linux build process 2025-06-09 18:23:15 -04:00
Anthony Green
a18d4e95d3 feat(.github/workflows): add step to wipe old snapshot assets in tarball.yml 2025-06-09 13:35:29 -04:00
Anthony Green
b9b8378556 fix(github-actions): correct regex in version extraction 2025-06-09 13:29:03 -04:00
Anthony Green
7ac6f14591 ci: change packages installed during workflow 2025-06-09 13:08:02 -04:00
Anthony Green
ceab352dfa ci: add installation of necessary tools to tarball workflow 2025-06-09 13:01:50 -04:00
Anthony Green
1f73aa507e refactor(.github/workflows/tarball): remove repeated job blocks 2025-06-09 12:56:19 -04:00
Anthony Green
7f5375d7c7 chore(workflows): update snapshot release description in tarball.yml 2025-06-09 12:55:09 -04:00
Anthony Green
2a5195bb2a chore(.github/workflows): update tarball.yml indentation 2025-06-09 12:54:55 -04:00
Anthony Green
2f535b8f74 chore(ci): update tarball workflow in GitHub Actions 2025-06-09 12:52:43 -04:00
29 changed files with 427 additions and 148 deletions

View File

@ -23,9 +23,9 @@ fi
function build_linux()
{
./autogen.sh
./configure ${HOST+--host=$HOST} ${CONFIGURE_OPTIONS} || cat */config.log
ls -l */config.log
cat */config.log
make
make dist
DEJAGNU=$(pwd)/.ci/site.exp BOARDSDIR=$(pwd)/.ci runtest --version

View File

@ -6,7 +6,7 @@ if [[ $RUNNER_OS != 'Linux' ]]; then
# brew update > brew-update.log 2>&1
# fix an issue with libtool on travis by reinstalling it
brew uninstall libtool;
brew install automake libtool dejagnu;
brew install automake libtool dejagnu gcc@15;
# Download and extract the rlgl client
wget -qO - https://rl.gl/cli/rlgl-darwin-amd64.tgz | \

View File

@ -5,6 +5,7 @@
BUILD-ERROR
RUNTIME-ERROR
FEATURE-REQUEST
QUESTION
# Operating systems
ANDROID

View File

@ -73,7 +73,7 @@ jobs:
fail-fast: false
matrix:
platform: [macos-13, macos-14, macos-15]
compilers: [CC=gcc CXX=g++, CC=clang CXX=clang++]
compilers: [CC=gcc-15 CXX=g++-15, CC=clang CXX=g++-15]
steps:
- run: git config --global core.autocrlf input

View File

@ -19,7 +19,7 @@ env:
# "info" field, or in Makefile.envs:
# https://github.com/pyodide/pyodide/blob/main/Makefile.envs#L2
PYTHON_VERSION: 3.12.7
EMSCRIPTEN_VERSION: 3.1.58
EMSCRIPTEN_VERSION: 4.0.10
EM_CACHE_FOLDER: emsdk-cache
jobs:
@ -39,6 +39,21 @@ jobs:
actions-cache-folder: ${{ env.EM_CACHE_FOLDER }}
test-dejagnu:
strategy:
matrix:
target:
- name: wasm32
host: wasm32
configureflags:
testflags:
- name: wasm64
host: wasm64
configureflags:
testflags: -sMEMORY64=1
- name: wasm64-2
host: wasm64
configureflags: WASM64_MEMORY64=2
testflags: -sMEMORY64=2
runs-on: ubuntu-24.04
needs: [setup-emsdk-cache]
steps:
@ -62,11 +77,26 @@ jobs:
version: ${{ env.EMSCRIPTEN_VERSION }}
actions-cache-folder: ${{ env.EM_CACHE_FOLDER }}
- name: Setup node.js
uses: actions/setup-node@v4
with:
node-version: 24
# This step updates emsdk's configuration file ".emscripten" to point to
# nodejs installed in the previous step.
- name: Configure emsdk to use the installed node.js
run: sed -i -E 's|NODE_JS = .*|NODE_JS = '"'$(which node)'"'|g' ${EMSDK}/.emscripten
- name: Install dependencies
run: sudo apt-get install dejagnu libltdl-dev
- name: Run tests
run: testsuite/emscripten/node-tests.sh
env:
TARGET_HOST: ${{ matrix.target.host }}
EXTRA_CONFIGURE_FLAGS: ${{ matrix.target.configureflags }}
EXTRA_CFLAGS: ${{ matrix.target.testflags }}
EXTRA_TEST_LDFLAGS: ${{ matrix.target.testflags }}
- name: Install rlgl and run
run: |
@ -77,6 +107,21 @@ jobs:
exit $?
build:
strategy:
matrix:
target:
- name: wasm32
host: wasm32
configureflags:
testflags:
- name: wasm64
host: wasm64
configureflags:
testflags: -sMEMORY64=1
- name: wasm64-2
host: wasm64
configureflags: WASM64_MEMORY64=2
testflags: -sMEMORY64=2
runs-on: ubuntu-24.04
needs: [setup-emsdk-cache]
steps:
@ -100,6 +145,9 @@ jobs:
- name: Build
run: ./testsuite/emscripten/build.sh
env:
TARGET_HOST: ${{ matrix.target.host }}
EXTRA_CONFIGURE_FLAGS: ${{ matrix.target.configureflags }}
- name: Build tests
run: |
@ -107,16 +155,23 @@ jobs:
cp -r testsuite/libffi.closures testsuite/libffi.closures.test
./testsuite/emscripten/build-tests.sh testsuite/libffi.call.test
./testsuite/emscripten/build-tests.sh testsuite/libffi.closures.test
env:
EXTRA_CFLAGS: ${{ matrix.target.testflags }}
EXTRA_LD_FLAGS: ${{ matrix.target.testflags }}
- name: Store artifacts
uses: actions/upload-artifact@v4
with:
name: built-tests
name: built-tests-${{ matrix.target.name }}
path: ./testsuite/libffi.c*/
test:
strategy:
matrix:
target:
- name: wasm32
- name: wasm64
- name: wasm64-2
browser: ["chrome"]
# FIXME: selenium can't find gecko driver for "firefox"
runs-on: ubuntu-24.04
@ -128,7 +183,7 @@ jobs:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: built-tests
name: built-tests-${{ matrix.target.name }}
path: ./testsuite/
- uses: conda-incubator/setup-miniconda@v3

View File

@ -8,33 +8,43 @@ jobs:
dist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # git describe needs full history
- name: Install autotools
run: sudo apt-get update && sudo apt-get -y install autoconf automake libtool texinfo libltdl-dev texlive
- name: Stamp snapshot version into configure.ac
- name: Install tools
run: |
VERSION="$(git describe --tags --long --match 'v[0-9]*' | sed -e 's/^v//' -e 's/-/.dev./' -e 's/-/+g/')"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
sudo apt update
sudo apt install texlive texinfo autoconf automake libtool libltdl-dev
# 1) AC_INIT second argument
# AC_INIT([libffi],[<old>],[bug-address])
sed -E -i "s/^(AC_INIT\(\[libffi\],\s*\[)[^]]+/\1$VERSION/" configure.ac
- uses: actions/checkout@v4
with: {fetch-depth: 0}
# 2) FFI_VERSION_STRING="..."
sed -E -i "s/^(FFI_VERSION_STRING=\")[^\"]+/\1$VERSION/" configure.ac
- name: Compute snapshot VERSION
id: ver
run: |
DESC=$(git describe --long --tags --match 'v[0-9]*' 2>/dev/null || echo "")
VERSION=$(echo "$DESC" | sed -E 's/^v//; s/-([0-9]+)-g/\.\1+g/')
if [[ -z "$VERSION" || "$VERSION" == "$DESC" ]]; then
VERSION="3.5.1-dev.0+g$(git rev-parse --short HEAD)"
fi
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: autogen
run: ./autogen.sh
- name: Patch configure.ac
run: |
sed -Ei "s/^(AC_INIT\(\[libffi\],\s*\[)[^]]+/\1${VERSION}/" configure.ac
sed -Ei "s/^(FFI_VERSION_STRING=\")[^\"]+/\1${VERSION}/" configure.ac
- name: Configure
run: ./configure
- run: autoreconf -fi
- run: ./configure
- run: make dist # produces libffi-${VERSION}.tar.gz
- name: Build dist tarball
run: make dist
- name: Wipe old snapshot assets
uses: mknejp/delete-release-assets@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: snapshots # ← whatever tag your nightly release uses
fail-if-no-assets: false
assets: |
libffi-*.tar.*
libffi-*.zip
- name: Create (or update) “snapshots” release
uses: softprops/action-gh-release@v2

View File

@ -63,11 +63,11 @@ noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h \
src/or1k/ffitarget.h src/pa/ffitarget.h \
src/powerpc/ffitarget.h src/powerpc/asm.h \
src/powerpc/ffi_powerpc.h src/powerpc/internal.h \
src/riscv/ffitarget.h \
src/riscv/ffitarget.h src/riscv/internal.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/wasm32/ffitarget.h \
src/wasm/ffitarget.h \
src/x86/ffitarget.h src/x86/internal.h src/x86/internal64.h \
src/x86/asmnames.h src/xtensa/ffitarget.h src/dlmalloc.c \
src/kvx/ffitarget.h src/kvx/asm.h \
@ -98,7 +98,7 @@ EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S \
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/wasm32/ffi.c \
src/wasm/ffi.c \
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 \

View File

@ -1,8 +1,7 @@
Status
======
libffi-3.5.0 was released on June 8, 2025. Check the libffi web
page for updates: <URL:http://sourceware.org/libffi/>.
libffi-3.5.2 was released on August 2, 2025.
What is libffi?
@ -103,6 +102,7 @@ tested:
| TILE-Gx/TILEPro | Linux | GCC |
| VAX | OpenBSD/vax | GCC |
| WASM32 | Emscripten | EMCC |
| WASM64 | Emscripten | EMCC |
| X86 | FreeBSD | GCC |
| X86 | GNU HURD | GCC |
| X86 | Interix | GCC |
@ -114,6 +114,7 @@ tested:
| X86 | Solaris | Oracle Solaris Studio C |
| X86 | Windows/Cygwin | GCC |
| X86 | Windows/MinGW | GCC |
| X86-64 | DragonFly BSD | GCC |
| X86-64 | FreeBSD | GCC |
| X86-64 | Linux | GCC |
| X86-64 | Linux/x32 | GCC |
@ -203,6 +204,14 @@ History
See the git log for details at http://github.com/libffi/libffi.
3.5.2 Aug-2-2025
Add wasm64 support.
Add DragonFly BSD support.
Ensure trampoline file descriptors are closed on exec.
3.5.1 Jun-10-2025
Fix symbol versioning error.
3.5.0 Jun-8-2025
Add FFI_VERSION_STRING and FFI_VERSION_NUMBER macros, as well
as ffi_get_version() and ffi_get_version_number() functions.

View File

@ -2,11 +2,11 @@ dnl Process this with autoconf to create configure
AC_PREREQ([2.68])
AC_INIT([libffi],[3.5.1-dev],[http://github.com/libffi/libffi/issues])
AC_INIT([libffi],[3.5.2],[http://github.com/libffi/libffi/issues])
AC_CONFIG_HEADERS([fficonfig.h])
FFI_VERSION_STRING="3.5.1-dev"
FFI_VERSION_NUMBER=30501
FFI_VERSION_STRING="3.5.2"
FFI_VERSION_NUMBER=30502
AC_SUBST(FFI_VERSION_STRING)
AC_SUBST(FFI_VERSION_NUMBER)
@ -123,6 +123,8 @@ AC_C_BIGENDIAN
GCC_AS_CFI_PSEUDO_OP
AC_ARG_VAR([WASM64_MEMORY64], [Used only for the wasm64 target. Set to 1 (default) or 2 for Emscripten's -sMEMORY64 mode])
case "$TARGET" in
SPARC)
AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs],
@ -182,6 +184,15 @@ case "$TARGET" in
[Define if the compiler uses zarch features.])
fi
;;
wasm64)
if test -z "$WASM64_MEMORY64"; then
WASM64_MEMORY64=1
fi
CFLAGS="$CFLAGS -sMEMORY64=$WASM64_MEMORY64"
;;
LOONGARCH64)
CFLAGS="$CFLAGS -mcmodel=medium"
;;
esac
AC_CACHE_CHECK([whether compiler supports pointer authentication],
@ -230,7 +241,7 @@ case "$target" in
[Cannot use PROT_EXEC on this target, so, we revert to
alternative means])
;;
*-apple-* | *-*-freebsd* | *-*-kfreebsd* | *-*-openbsd* | *-pc-solaris* | *-linux-android*)
*-apple-* | *-*-dragonfly* | *-*-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])
@ -384,7 +395,8 @@ case "$target" in
fi
;;
*arm*-*-linux-* | aarch64*-*-linux-* | i*86-*-linux-* | x86_64-*-linux-* \
| loongarch*-*-linux-* | s390x*-linux-* | powerpc*-linux-*)
| loongarch*-*-linux-* | s390x*-linux-* | powerpc*-linux-* \
| riscv*-linux-*)
AC_DEFINE(FFI_EXEC_STATIC_TRAMP, 1,
[Define this if you want statically defined trampolines])
;;

View File

@ -261,7 +261,12 @@ case "${host}" in
;;
wasm32-*-*)
TARGET=wasm32; TARGETDIR=wasm32
TARGET=wasm32; TARGETDIR=wasm
SOURCES="ffi.c"
;;
wasm64-*-*)
TARGET=wasm64; TARGETDIR=wasm
SOURCES="ffi.c"
;;

View File

@ -1,4 +1,4 @@
@set UPDATED 8 June 2025
@set UPDATED-MONTH June 2025
@set EDITION 3.5.0
@set VERSION 3.5.0
@set UPDATED 2 August 2025
@set UPDATED-MONTH August 2025
@set EDITION 3.5.2
@set VERSION 3.5.2

View File

@ -23,13 +23,6 @@ LIBFFI_BASE_8.0 {
ffi_type_longdouble;
ffi_type_pointer;
/* Exported functions. */
ffi_get_version;
ffi_get_version_number;
ffi_get_default_abi;
ffi_get_closure_size;
ffi_call;
ffi_prep_cif;
ffi_prep_cif_var;
@ -52,6 +45,19 @@ LIBFFI_BASE_8.0 {
*;
};
/* ----------------------------------------------------------------------
Symbols **added in libffi 3.5.0**.
Give them a fresh namespace so that package managers notice when
code requires a newer libffi than 3.4.x.
-------------------------------------------------------------------- */
LIBFFI_BASE_8.1 {
global:
ffi_get_version;
ffi_get_version_number;
ffi_get_default_abi;
ffi_get_closure_size;
} LIBFFI_BASE_8.0;
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
LIBFFI_COMPLEX_8.0 {
global:

View File

@ -74,6 +74,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
.text
.align 4
#if defined(__ARM_FEATURE_GCS_DEFAULT) && __ARM_FEATURE_GCS_DEFAULT == 1
#define GNU_PROPERTY_AARCH64_GCS (1<<2)
#else
#define GNU_PROPERTY_AARCH64_GCS 0 /* No GCS */
#endif
/* ffi_call_SYSV
extern void ffi_call_SYSV (void *stack, void *frame,
void (*fn)(void), void *rvalue,
@ -692,7 +698,7 @@ CNAME(ffi_go_closure_SYSV):
.asciz "GNU";
.long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
.long 4;
.long GNU_PROPERTY_AARCH64_BTI | GNU_PROPERTY_AARCH64_POINTER_AUTH;
.long GNU_PROPERTY_AARCH64_BTI | GNU_PROPERTY_AARCH64_POINTER_AUTH | GNU_PROPERTY_AARCH64_GCS;
.long 0;
.popsection;
#endif

View File

@ -120,7 +120,7 @@
#endif
#ifndef __clang__
#ifdef __ELF__
/* We require interworking on LDM, which implies ARMv5T,
which implies the existance of BLX. */
.arch armv5t

View File

@ -29,6 +29,8 @@
#include <ffi.h>
#include <ffi_common.h>
#include "internal.h"
#include <tramp.h>
#include <stdlib.h>
#include <stdint.h>
@ -424,34 +426,44 @@ extern void ffi_closure_asm(void) FFI_HIDDEN;
ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc)
{
uint32_t *tramp = (uint32_t *) &closure->tramp[0];
uint64_t fn = (uint64_t) (uintptr_t) ffi_closure_asm;
if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI)
return FFI_BAD_ABI;
/* we will call ffi_closure_inner with codeloc, not closure, but as long
as the memory is readable it should work */
tramp[0] = 0x00000317; /* auipc t1, 0 (i.e. t0 <- codeloc) */
#if __SIZEOF_POINTER__ == 8
tramp[1] = 0x01033383; /* ld t2, 16(t1) */
#else
tramp[1] = 0x01032383; /* lw t2, 16(t1) */
#ifdef FFI_EXEC_STATIC_TRAMP
if (ffi_tramp_is_present (closure))
{
/* Initialize the static trampoline's parameters. */
void (*dest)(void) = ffi_closure_asm;
ffi_tramp_set_parms (closure->ftramp, dest, closure);
}
else
#endif
tramp[2] = 0x00038067; /* jr t2 */
tramp[3] = 0x00000013; /* nop */
tramp[4] = fn;
tramp[5] = fn >> 32;
{
uint32_t *tramp = (uint32_t *) &closure->tramp[0];
uint64_t fn = (uint64_t) (uintptr_t) ffi_closure_asm;
/* we will call ffi_closure_inner with codeloc, not closure, but as long
as the memory is readable it should work */
tramp[0] = 0x00000317; /* auipc t1, 0 (i.e. t0 <- codeloc) */
#if __SIZEOF_POINTER__ == 8
tramp[1] = 0x01033383; /* ld t2, 16(t1) */
#else
tramp[1] = 0x01032383; /* lw t2, 16(t1) */
#endif
tramp[2] = 0x00038067; /* jr t2 */
tramp[3] = 0x00000013; /* nop */
tramp[4] = fn;
tramp[5] = fn >> 32;
#if !defined(__FreeBSD__)
__builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE);
#endif
}
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
#if !defined(__FreeBSD__)
__builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE);
#endif
return FFI_OK;
}
@ -512,3 +524,14 @@ ffi_closure_inner (ffi_cif *cif,
marshal(&cb, cif->rtype, 0, rvalue);
}
}
#ifdef FFI_EXEC_STATIC_TRAMP
void *
ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
{
extern void *trampoline_code_table;
*tramp_size = RISCV_TRAMP_SIZE;
*map_size = RISCV_TRAMP_MAP_SIZE;
return &trampoline_code_table;
}
#endif

7
src/riscv/internal.h Normal file
View File

@ -0,0 +1,7 @@
#ifdef FFI_EXEC_STATIC_TRAMP
/* For the trampoline table mapping, a mapping size of 4K (base page size)
is chosen. */
#define RISCV_TRAMP_MAP_SHIFT 12
#define RISCV_TRAMP_MAP_SIZE (1 << RISCV_TRAMP_MAP_SHIFT)
#define RISCV_TRAMP_SIZE 16
#endif /* FFI_EXEC_STATIC_TRAMP */

View File

@ -29,6 +29,7 @@
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#include "internal.h"
/* Define aliases so that we can handle all ABIs uniformly */
@ -291,3 +292,26 @@ ffi_go_closure_asm:
ret
.cfi_endproc
.size ffi_go_closure_asm, .-ffi_go_closure_asm
#ifdef FFI_EXEC_STATIC_TRAMP
/*
trampoline_code_table.
*/
.globl trampoline_code_table
.hidden trampoline_code_table
.type trampoline_code_table, @function
.align RISCV_TRAMP_MAP_SHIFT
trampoline_code_table:
.option push
# Do not allow the jr insn to be encoded as c.jr for alignment purposes
.option norvc
.rept RISCV_TRAMP_MAP_SIZE / RISCV_TRAMP_SIZE
auipc t2, RISCV_TRAMP_MAP_SIZE >> 12
LARG t1, 0(t2)
LARG t2, PTRS(t2)
jr t2
.endr
.option pop
.size trampoline_code_table,.-trampoline_code_table
.align RISCV_TRAMP_MAP_SHIFT
#endif /* FFI_EXEC_STATIC_TRAMP */

View File

@ -209,6 +209,11 @@ ffi_tramp_get_libffi (void)
unsigned long start, end, offset, inode;
uintptr_t addr = (uintptr_t) tramp_globals.text;
int nfields, found;
int open_flags = O_RDONLY;
#ifdef O_CLOEXEC
open_flags |= O_CLOEXEC;
#endif
snprintf (file, PATH_MAX, "/proc/%d/maps", getpid());
fp = fopen (file, "r");
@ -236,7 +241,7 @@ ffi_tramp_get_libffi (void)
if (!found)
return 0;
tramp_globals.fd = open (file, O_RDONLY);
tramp_globals.fd = open (file, open_flags);
if (tramp_globals.fd == -1)
return 0;

View File

@ -59,16 +59,29 @@ EM_JS_DEPS(libffi, "$getWasmTableEntry,$setWasmTableEntry,$getEmptyTableSlot,$co
offsetof(struct, field) == offset, \
"Memory layout of '" #struct "' has changed: '" #field "' is in an unexpected location");
#if __SIZEOF_POINTER__ == 4
#define FFI_EMSCRIPTEN_ABI FFI_WASM32_EMSCRIPTEN
#define PTR_SIG 'i'
#define DEC_PTR(p) p
#define ENC_PTR(p) p
#define DEREF_PTR(addr, offset) DEREF_U32(addr, offset)
#define DEREF_PTR_NUMBER(addr, offset) DEREF_PTR(addr, offset)
CHECK_FIELD_OFFSET(ffi_cif, abi, 4*0);
CHECK_FIELD_OFFSET(ffi_cif, nargs, 4*1);
CHECK_FIELD_OFFSET(ffi_cif, arg_types, 4*2);
CHECK_FIELD_OFFSET(ffi_cif, rtype, 4*3);
CHECK_FIELD_OFFSET(ffi_cif, flags, 4*5);
CHECK_FIELD_OFFSET(ffi_cif, nfixedargs, 4*6);
#define CIF__ABI(addr) DEREF_U32(addr, 0)
#define CIF__NARGS(addr) DEREF_U32(addr, 1)
#define CIF__ARGTYPES(addr) DEREF_U32(addr, 2)
#define CIF__RTYPE(addr) DEREF_U32(addr, 3)
#define CIF__FLAGS(addr) DEREF_U32(addr, 5)
#define CIF__NFIXEDARGS(addr) DEREF_U32(addr, 6)
CHECK_FIELD_OFFSET(ffi_type, size, 0);
@ -81,6 +94,49 @@ CHECK_FIELD_OFFSET(ffi_type, elements, 8);
#define FFI_TYPE__TYPEID(addr) DEREF_U16(addr + 6, 0)
#define FFI_TYPE__ELEMENTS(addr) DEREF_U32(addr + 8, 0)
#elif __SIZEOF_POINTER__ == 8
#define FFI_EMSCRIPTEN_ABI FFI_WASM64_EMSCRIPTEN
#define PTR_SIG 'j'
// DEC_PTR casts a pointer value (comming from Wasm) represented as BigInt (i64) to Number (i53).
// This should be used for a pointer that is expected to be within the i53 range. If the pointer
// value is outside the Number's range, the value will become NaN.
#define DEC_PTR(p) bigintToI53Checked(p)
// ENC_PTR casts a pointer value represented as Number to BigInt (i64)
#define ENC_PTR(p) BigInt(p)
#define DEREF_PTR(addr, offset) DEREF_U64(addr, offset)
#define DEREF_PTR_NUMBER(addr, offset) DEC_PTR(DEREF_PTR(addr, offset))
CHECK_FIELD_OFFSET(ffi_cif, abi, 0);
CHECK_FIELD_OFFSET(ffi_cif, nargs, 4);
CHECK_FIELD_OFFSET(ffi_cif, arg_types, 8);
CHECK_FIELD_OFFSET(ffi_cif, rtype, 16);
CHECK_FIELD_OFFSET(ffi_cif, flags, 28);
CHECK_FIELD_OFFSET(ffi_cif, nfixedargs, 32);
#define CIF__ABI(addr) DEREF_U32(addr, 0)
#define CIF__NARGS(addr) DEREF_U32(addr + 4, 0)
#define CIF__ARGTYPES(addr) DEREF_U64(addr + 8, 0)
#define CIF__RTYPE(addr) DEREF_U64(addr + 16, 0)
#define CIF__FLAGS(addr) DEREF_U32(addr + 28, 0)
#define CIF__NFIXEDARGS(addr) DEREF_U32(addr + 32, 0)
CHECK_FIELD_OFFSET(ffi_type, size, 0);
CHECK_FIELD_OFFSET(ffi_type, alignment, 8);
CHECK_FIELD_OFFSET(ffi_type, type, 10);
CHECK_FIELD_OFFSET(ffi_type, elements, 16);
#define FFI_TYPE__SIZE(addr) DEREF_U64(addr, 0)
#define FFI_TYPE__ALIGN(addr) DEREF_U16(addr + 8, 0)
#define FFI_TYPE__TYPEID(addr) DEREF_U16(addr + 10, 0)
#define FFI_TYPE__ELEMENTS(addr) DEREF_U64(addr + 16, 0)
#else
#error "Unknown pointer size"
#endif
#define ALIGN_ADDRESS(addr, align) (addr &= (~((align) - 1)))
#define STACK_ALLOC(stack, size, align) ((stack -= (size)), ALIGN_ADDRESS(stack, align))
@ -100,7 +156,7 @@ _Static_assert(FFI_BAD_TYPEDEF_MACRO == FFI_BAD_TYPEDEF, "FFI_BAD_TYPEDEF must b
ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif *cif)
{
if (cif->abi != FFI_WASM32_EMSCRIPTEN)
if (cif->abi != FFI_EMSCRIPTEN_ABI)
return FFI_BAD_ABI;
// This is called after ffi_prep_cif_machdep_var so we need to avoid
// overwriting cif->nfixedargs.
@ -144,6 +200,7 @@ ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs)
EM_JS_MACROS(
void,
unbox_small_structs, (ffi_type type_ptr), {
type_ptr = DEC_PTR(type_ptr);
var type_id = FFI_TYPE__TYPEID(type_ptr);
while (type_id === FFI_TYPE_STRUCT) {
// Don't unbox single element structs if they are bigger than 16 bytes. This
@ -156,15 +213,15 @@ unbox_small_structs, (ffi_type type_ptr), {
//
// See the Python comment here:
// https://github.com/python/cpython/blob/a16a9f978f42b8a09297c1efbf33877f6388c403/Modules/_ctypes/stgdict.c#L718-L779
if (FFI_TYPE__SIZE(type_ptr) > 16) {
if (DEC_PTR(FFI_TYPE__SIZE(type_ptr)) > 16) {
break;
}
var elements = FFI_TYPE__ELEMENTS(type_ptr);
var first_element = DEREF_U32(elements, 0);
var elements = DEC_PTR(FFI_TYPE__ELEMENTS(type_ptr));
var first_element = DEREF_PTR_NUMBER(elements, 0);
if (first_element === 0) {
type_id = FFI_TYPE_VOID;
break;
} else if (DEREF_U32(elements, 1) === 0) {
} else if (DEREF_PTR_NUMBER(elements, 1) === 0) {
type_ptr = first_element;
type_id = FFI_TYPE__TYPEID(first_element);
} else {
@ -178,10 +235,15 @@ EM_JS_MACROS(
void,
ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
{
cif = DEC_PTR(cif);
fn = DEC_PTR(fn);
rvalue = DEC_PTR(rvalue);
avalue = DEC_PTR(avalue);
var abi = CIF__ABI(cif);
var nargs = CIF__NARGS(cif);
var nfixedargs = CIF__NFIXEDARGS(cif);
var arg_types_ptr = CIF__ARGTYPES(cif);
var arg_types_ptr = DEC_PTR(CIF__ARGTYPES(cif));
var flags = CIF__FLAGS(cif);
var rtype_unboxed = unbox_small_structs(CIF__RTYPE(cif));
var rtype_ptr = rtype_unboxed[0];
var rtype_id = rtype_unboxed[1];
@ -205,7 +267,7 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
// just use this. We also mark a flag that we don't need to convert the return
// value of the dynamic call back to C.
if (rtype_id === FFI_TYPE_LONGDOUBLE || rtype_id === FFI_TYPE_STRUCT) {
args.push(rvalue);
args.push(ENC_PTR(rvalue));
ret_by_arg = true;
}
@ -214,8 +276,8 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
// Javascript to C automatically, here we manually do the inverse conversion
// from C to Javascript.
for (var i = 0; i < nfixedargs; i++) {
var arg_ptr = DEREF_U32(avalue, i);
var arg_unboxed = unbox_small_structs(DEREF_U32(arg_types_ptr, i));
var arg_ptr = DEREF_PTR_NUMBER(avalue, i);
var arg_unboxed = unbox_small_structs(DEREF_PTR(arg_types_ptr, i));
var arg_type_ptr = arg_unboxed[0];
var arg_type_id = arg_unboxed[1];
@ -226,7 +288,6 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER:
args.push(DEREF_U32(arg_ptr, 0));
break;
case FFI_TYPE_FLOAT:
@ -260,11 +321,14 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
// Nontrivial structs are passed by pointer.
// Have to copy the struct onto the stack though because C ABI says it's
// call by value.
var size = FFI_TYPE__SIZE(arg_type_ptr);
var size = DEC_PTR(FFI_TYPE__SIZE(arg_type_ptr));
var align = FFI_TYPE__ALIGN(arg_type_ptr);
STACK_ALLOC(cur_stack_ptr, size, align);
HEAP8.subarray(cur_stack_ptr, cur_stack_ptr+size).set(HEAP8.subarray(arg_ptr, arg_ptr + size));
args.push(cur_stack_ptr);
args.push(ENC_PTR(cur_stack_ptr));
break;
case FFI_TYPE_POINTER:
args.push(DEREF_PTR(arg_ptr, 0));
break;
case FFI_TYPE_COMPLEX:
throw new Error('complex marshalling nyi');
@ -282,11 +346,11 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
// We don't have any way of knowing how many args were actually passed, so we
// just always copy extra nonsense past the end. The ownwards call will know
// not to look at it.
if (nfixedargs != nargs) {
if (flags & VARARGS_FLAG) {
var struct_arg_info = [];
for (var i = nargs - 1; i >= nfixedargs; i--) {
var arg_ptr = DEREF_U32(avalue, i);
var arg_unboxed = unbox_small_structs(DEREF_U32(arg_types_ptr, i));
var arg_ptr = DEREF_PTR_NUMBER(avalue, i);
var arg_unboxed = unbox_small_structs(DEREF_PTR(arg_types_ptr, i));
var arg_type_ptr = arg_unboxed[0];
var arg_type_id = arg_unboxed[1];
switch (arg_type_id) {
@ -303,7 +367,6 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
case FFI_TYPE_FLOAT:
STACK_ALLOC(cur_stack_ptr, 4, 4);
DEREF_U32(cur_stack_ptr, 0) = DEREF_U32(arg_ptr, 0);
@ -326,8 +389,12 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
// Again, struct must be passed by pointer.
// But ABI is by value, so have to copy struct onto stack.
// Currently arguments are going onto stack so we can't put it there now. Come back for this.
STACK_ALLOC(cur_stack_ptr, 4, 4);
struct_arg_info.push([cur_stack_ptr, arg_ptr, FFI_TYPE__SIZE(arg_type_ptr), FFI_TYPE__ALIGN(arg_type_ptr)]);
STACK_ALLOC(cur_stack_ptr, __SIZEOF_POINTER__, __SIZEOF_POINTER__);
struct_arg_info.push([cur_stack_ptr, arg_ptr, DEC_PTR(FFI_TYPE__SIZE(arg_type_ptr)), FFI_TYPE__ALIGN(arg_type_ptr)]);
break;
case FFI_TYPE_POINTER:
STACK_ALLOC(cur_stack_ptr, __SIZEOF_POINTER__, __SIZEOF_POINTER__);
DEREF_PTR(cur_stack_ptr, 0) = DEREF_PTR(arg_ptr, 0);
break;
case FFI_TYPE_COMPLEX:
throw new Error('complex arg marshalling nyi');
@ -336,7 +403,7 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
}
}
// extra normal argument which is the pointer to the varargs.
args.push(cur_stack_ptr);
args.push(ENC_PTR(cur_stack_ptr));
// Now allocate variable struct args on stack too.
for (var i = 0; i < struct_arg_info.length; i++) {
var struct_info = struct_arg_info[i];
@ -346,7 +413,7 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
var align = struct_info[3];
STACK_ALLOC(cur_stack_ptr, size, align);
HEAP8.subarray(cur_stack_ptr, cur_stack_ptr+size).set(HEAP8.subarray(arg_ptr, arg_ptr + size));
DEREF_U32(arg_target, 0) = cur_stack_ptr;
DEREF_PTR(arg_target, 0) = ENC_PTR(cur_stack_ptr);
}
}
stackRestore(cur_stack_ptr);
@ -371,7 +438,6 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
DEREF_U32(rvalue, 0) = result;
break;
case FFI_TYPE_FLOAT:
@ -392,6 +458,9 @@ ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
case FFI_TYPE_SINT64:
DEREF_U64(rvalue, 0) = result;
break;
case FFI_TYPE_POINTER:
DEREF_PTR(rvalue, 0) = result;
break;
case FFI_TYPE_COMPLEX:
throw new Error('complex ret marshalling nyi');
default:
@ -403,6 +472,8 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) {
ffi_call_js(cif, fn, rvalue, avalue);
}
#if __SIZEOF_POINTER__ == 4
CHECK_FIELD_OFFSET(ffi_closure, ftramp, 4*0);
CHECK_FIELD_OFFSET(ffi_closure, cif, 4*1);
CHECK_FIELD_OFFSET(ffi_closure, fun, 4*2);
@ -413,12 +484,30 @@ CHECK_FIELD_OFFSET(ffi_closure, user_data, 4*3);
#define CLOSURE__fun(addr) DEREF_U32(addr, 2)
#define CLOSURE__user_data(addr) DEREF_U32(addr, 3)
#elif __SIZEOF_POINTER__ == 8
CHECK_FIELD_OFFSET(ffi_closure, ftramp, 0);
CHECK_FIELD_OFFSET(ffi_closure, cif, 8);
CHECK_FIELD_OFFSET(ffi_closure, fun, 16);
CHECK_FIELD_OFFSET(ffi_closure, user_data, 24);
#define CLOSURE__wrapper(addr) DEREF_U64(addr, 0)
#define CLOSURE__cif(addr) DEREF_U64(addr, 1)
#define CLOSURE__fun(addr) DEREF_U64(addr, 2)
#define CLOSURE__user_data(addr) DEREF_U64(addr, 3)
#else
#error "Unknown pointer size"
#endif
EM_JS_MACROS(void *, ffi_closure_alloc_js, (size_t size, void **code), {
size = DEC_PTR(size);
code = DEC_PTR(code);
var closure = _malloc(size);
var index = getEmptyTableSlot();
DEREF_U32(code, 0) = index;
CLOSURE__wrapper(closure) = index;
return closure;
DEREF_PTR(code, 0) = ENC_PTR(index);
CLOSURE__wrapper(closure) = ENC_PTR(index);
return ENC_PTR(closure);
})
void * __attribute__ ((visibility ("default")))
@ -427,7 +516,8 @@ ffi_closure_alloc(size_t size, void **code) {
}
EM_JS_MACROS(void, ffi_closure_free_js, (void *closure), {
var index = CLOSURE__wrapper(closure);
closure = DEC_PTR(closure);
var index = DEC_PTR(CLOSURE__wrapper(closure));
freeTableIndexes.push(index);
_free(closure);
})
@ -442,10 +532,15 @@ ffi_status,
ffi_prep_closure_loc_js,
(ffi_closure *closure, ffi_cif *cif, void *fun, void *user_data, void *codeloc),
{
closure = DEC_PTR(closure);
cif = DEC_PTR(cif);
fun = DEC_PTR(fun);
user_data = DEC_PTR(user_data);
codeloc = DEC_PTR(codeloc);
var abi = CIF__ABI(cif);
var nargs = CIF__NARGS(cif);
var nfixedargs = CIF__NFIXEDARGS(cif);
var arg_types_ptr = CIF__ARGTYPES(cif);
var arg_types_ptr = DEC_PTR(CIF__ARGTYPES(cif));
var rtype_unboxed = unbox_small_structs(CIF__RTYPE(cif));
var rtype_ptr = rtype_unboxed[0];
var rtype_id = rtype_unboxed[1];
@ -461,7 +556,7 @@ ffi_prep_closure_loc_js,
case FFI_TYPE_STRUCT:
case FFI_TYPE_LONGDOUBLE:
// Return via a first pointer argument.
sig = 'vi';
sig = 'v' + PTR_SIG;
ret_by_arg = true;
break;
case FFI_TYPE_INT:
@ -471,7 +566,6 @@ ffi_prep_closure_loc_js,
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
sig = 'i';
break;
case FFI_TYPE_FLOAT:
@ -484,6 +578,9 @@ ffi_prep_closure_loc_js,
case FFI_TYPE_SINT64:
sig = 'j';
break;
case FFI_TYPE_POINTER:
sig = PTR_SIG;
break;
case FFI_TYPE_COMPLEX:
throw new Error('complex ret marshalling nyi');
default:
@ -492,11 +589,11 @@ ffi_prep_closure_loc_js,
var unboxed_arg_type_id_list = [];
var unboxed_arg_type_info_list = [];
for (var i = 0; i < nargs; i++) {
var arg_unboxed = unbox_small_structs(DEREF_U32(arg_types_ptr, i));
var arg_unboxed = unbox_small_structs(DEREF_PTR(arg_types_ptr, i));
var arg_type_ptr = arg_unboxed[0];
var arg_type_id = arg_unboxed[1];
unboxed_arg_type_id_list.push(arg_type_id);
unboxed_arg_type_info_list.push([FFI_TYPE__SIZE(arg_type_ptr), FFI_TYPE__ALIGN(arg_type_ptr)]);
unboxed_arg_type_info_list.push([DEC_PTR(FFI_TYPE__SIZE(arg_type_ptr)), FFI_TYPE__ALIGN(arg_type_ptr)]);
}
for (var i = 0; i < nfixedargs; i++) {
switch (unboxed_arg_type_id_list[i]) {
@ -507,8 +604,6 @@ ffi_prep_closure_loc_js,
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
case FFI_TYPE_STRUCT:
sig += 'i';
break;
case FFI_TYPE_FLOAT:
@ -524,6 +619,10 @@ ffi_prep_closure_loc_js,
case FFI_TYPE_SINT64:
sig += 'j';
break;
case FFI_TYPE_STRUCT:
case FFI_TYPE_POINTER:
sig += PTR_SIG;
break;
case FFI_TYPE_COMPLEX:
throw new Error('complex marshalling nyi');
default:
@ -532,7 +631,7 @@ ffi_prep_closure_loc_js,
}
if (nfixedargs < nargs) {
// extra pointer to varargs stack
sig += 'i';
sig += PTR_SIG;
}
LOG_DEBUG("CREATE_CLOSURE", "sig:", sig);
function trampoline() {
@ -551,7 +650,7 @@ ffi_prep_closure_loc_js,
STACK_ALLOC(cur_ptr, 8, 8);
ret_ptr = cur_ptr;
}
cur_ptr -= 4 * nargs;
cur_ptr -= __SIZEOF_POINTER__ * nargs;
var args_ptr = cur_ptr;
var carg_idx = 0;
// Here we either have the actual argument, or a pair of BigInts for long
@ -572,58 +671,62 @@ ffi_prep_closure_loc_js,
case FFI_TYPE_SINT8:
// Bad things happen if we don't align to 4 here
STACK_ALLOC(cur_ptr, 1, 4);
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_U8(cur_ptr, 0) = cur_arg;
break;
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
// Bad things happen if we don't align to 4 here
STACK_ALLOC(cur_ptr, 2, 4);
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_U16(cur_ptr, 0) = cur_arg;
break;
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
STACK_ALLOC(cur_ptr, 4, 4);
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_U32(cur_ptr, 0) = cur_arg;
break;
case FFI_TYPE_STRUCT:
// cur_arg is already a pointer to struct
// copy it onto stack to pass by value
STACK_ALLOC(cur_ptr, arg_size, arg_align);
HEAP8.subarray(cur_ptr, cur_ptr + arg_size).set(HEAP8.subarray(cur_arg, cur_arg + arg_size));
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
HEAP8.subarray(cur_ptr, cur_ptr + arg_size).set(HEAP8.subarray(DEC_PTR(cur_arg), DEC_PTR(cur_arg) + arg_size));
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
break;
case FFI_TYPE_FLOAT:
STACK_ALLOC(cur_ptr, 4, 4);
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_F32(cur_ptr, 0) = cur_arg;
break;
case FFI_TYPE_DOUBLE:
STACK_ALLOC(cur_ptr, 8, 8);
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_F64(cur_ptr, 0) = cur_arg;
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
STACK_ALLOC(cur_ptr, 8, 8);
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_U64(cur_ptr, 0) = cur_arg;
break;
case FFI_TYPE_LONGDOUBLE:
STACK_ALLOC(cur_ptr, 16, 8);
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_U64(cur_ptr, 0) = cur_arg;
cur_arg = args[jsarg_idx++];
DEREF_U64(cur_ptr, 1) = cur_arg;
break;
case FFI_TYPE_POINTER:
STACK_ALLOC(cur_ptr, __SIZEOF_POINTER__, __SIZEOF_POINTER__);
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
DEREF_PTR(cur_ptr, 0) = cur_arg;
break;
}
}
// If its a varargs call, last js argument is a pointer to the varargs.
var varargs = args[args.length - 1];
var varargs = DEC_PTR(args[args.length - 1]);
// We have no way of knowing how many varargs were actually provided, this
// fills the rest of the stack space allocated with nonsense. The onward
// call will know to ignore the nonsense.
@ -639,20 +742,20 @@ ffi_prep_closure_loc_js,
if (arg_type_id === FFI_TYPE_STRUCT) {
// In this case varargs is a pointer to pointer to struct so we need to
// deref once
var struct_ptr = DEREF_U32(varargs, 0);
var struct_ptr = DEREF_PTR_NUMBER(varargs, 0);
STACK_ALLOC(cur_ptr, arg_size, arg_align);
HEAP8.subarray(cur_ptr, cur_ptr + arg_size).set(HEAP8.subarray(struct_ptr, struct_ptr + arg_size));
DEREF_U32(args_ptr, carg_idx) = cur_ptr;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
} else {
DEREF_U32(args_ptr, carg_idx) = varargs;
DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(varargs);
}
varargs += 4;
varargs += __SIZEOF_POINTER__;
}
stackRestore(cur_ptr);
stackAlloc(0); // stackAlloc enforces alignment invariants on the stack pointer
LOG_DEBUG("CALL_CLOSURE", "closure:", closure, "fptr", CLOSURE__fun(closure), "cif", CLOSURE__cif(closure));
getWasmTableEntry(CLOSURE__fun(closure))(
CLOSURE__cif(closure), ret_ptr, args_ptr,
CLOSURE__cif(closure), ENC_PTR(ret_ptr), ENC_PTR(args_ptr),
CLOSURE__user_data(closure)
);
stackRestore(orig_stack_ptr);
@ -677,9 +780,9 @@ ffi_prep_closure_loc_js,
return FFI_BAD_TYPEDEF_MACRO;
}
setWasmTableEntry(codeloc, wasm_trampoline);
CLOSURE__cif(closure) = cif;
CLOSURE__fun(closure) = fun;
CLOSURE__user_data(closure) = user_data;
CLOSURE__cif(closure) = ENC_PTR(cif);
CLOSURE__fun(closure) = ENC_PTR(fun);
CLOSURE__user_data(closure) = ENC_PTR(user_data);
return FFI_OK_MACRO;
})
@ -688,7 +791,7 @@ ffi_prep_closure_loc_js,
ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif,
void (*fun)(ffi_cif *, void *, void **, void *),
void *user_data, void *codeloc) {
if (cif->abi != FFI_WASM32_EMSCRIPTEN)
if (cif->abi != FFI_EMSCRIPTEN_ABI)
return FFI_BAD_ABI;
return ffi_prep_closure_loc_js(closure, cif, (void *)fun, user_data,
codeloc);

View File

@ -42,14 +42,31 @@ typedef void (*ffi_fp)(void);
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
#if __SIZEOF_POINTER__ == 4
FFI_WASM32, // "raw", no structures, varargs, or closures (not implemented!)
FFI_WASM32_EMSCRIPTEN, // structures, varargs, and split 64-bit params
#elif __SIZEOF_POINTER__ == 8
FFI_WASM64,
FFI_WASM64_EMSCRIPTEN,
#else
#error "Unknown pointer size"
#endif
FFI_LAST_ABI,
#if __SIZEOF_POINTER__ == 4
#ifdef __EMSCRIPTEN__
FFI_DEFAULT_ABI = FFI_WASM32_EMSCRIPTEN
#else
FFI_DEFAULT_ABI = FFI_WASM32
#endif
#elif __SIZEOF_POINTER__ == 8
#ifdef __EMSCRIPTEN__
FFI_DEFAULT_ABI = FFI_WASM64_EMSCRIPTEN
#else
FFI_DEFAULT_ABI = FFI_WASM64
#endif
#else
#error "Unknown pointer size"
#endif
} ffi_abi;
#define FFI_CLOSURES 1

View File

@ -41,9 +41,6 @@
#if defined (X86_64) && defined (__i386__)
#undef X86_64
#warning ******************************************************
#warning ********** X86 IS DEFINED ****************************
#warning ******************************************************
#define X86
#endif

View File

@ -458,9 +458,7 @@ L(UW24):
L(UW25):
# cfi_def_cfa_offset(closure_FS + 4)
FFI_CLOSURE_SAVE_REGS
movl closure_FS-4(%esp), %ecx /* load retaddr */
movl closure_FS(%esp), %eax /* load closure */
movl %ecx, closure_FS(%esp) /* move retaddr */
movl closure_FS-4(%esp), %eax /* load closure */
jmp L(do_closure_REGISTER)
L(UW26):
# cfi_endproc

View File

@ -394,9 +394,7 @@ L(UW24):
L(UW25):
/* cfi_def_cfa_offset(closure_FS + 4) */
FFI_CLOSURE_SAVE_REGS
mov ecx, [esp+closure_FS-4] /* load retaddr */
mov eax, [esp+closure_FS] /* load closure */
mov [esp+closure_FS], ecx /* move retaddr */
mov eax, [esp+closure_FS-4] /* load closure */
jmp L(do_closure_REGISTER)
L(UW26):
/* cfi_endproc */

View File

@ -36,11 +36,11 @@ export PKG_CONFIG_PATH="$TARGET/lib/pkgconfig"
export EM_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
# Specific variables for cross-compilation
export CHOST="wasm32-unknown-linux" # wasm32-unknown-emscripten
export CHOST="${TARGET_HOST}-unknown-linux" # wasm32-unknown-emscripten
autoreconf -fiv
emconfigure ./configure --host=$CHOST --prefix="$TARGET" --enable-static --disable-shared --disable-dependency-tracking \
--disable-builddir --disable-multi-os-directory --disable-raw-api --disable-docs
--disable-builddir --disable-multi-os-directory --disable-raw-api --disable-docs ${EXTRA_CONFIGURE_FLAGS}
make install
cp fficonfig.h target/include/
cp include/ffi_common.h target/include/

View File

@ -8,16 +8,16 @@ fi
# Common compiler flags
export CFLAGS="-fPIC $EXTRA_CFLAGS"
export CXXFLAGS="$CFLAGS -sNO_DISABLE_EXCEPTION_CATCHING $EXTRA_CXXFLAGS"
export LDFLAGS="-sEXPORTED_FUNCTIONS=_main,_malloc,_free -sALLOW_TABLE_GROWTH -sASSERTIONS -sNO_DISABLE_EXCEPTION_CATCHING -sWASM_BIGINT"
export LDFLAGS="-sEXPORTED_FUNCTIONS=_main,_malloc,_free -sALLOW_TABLE_GROWTH -sASSERTIONS -sNO_DISABLE_EXCEPTION_CATCHING -sWASM_BIGINT -Wno-main"
# Specific variables for cross-compilation
export CHOST="wasm32-unknown-linux" # wasm32-unknown-emscripten
export CHOST="${TARGET_HOST}-unknown-linux" # wasm32-unknown-emscripten
autoreconf -fiv
emconfigure ./configure --prefix="$(pwd)/target" --host=$CHOST --enable-static --disable-shared \
--disable-builddir --disable-multi-os-directory --disable-raw-api --disable-docs ||
--disable-builddir --disable-multi-os-directory --disable-raw-api --disable-docs ${EXTRA_CONFIGURE_FLAGS} ||
(cat config.log && exit 1)
make
EMMAKEN_JUST_CONFIGURE=1 emmake make check \
RUNTESTFLAGS="LDFLAGS_FOR_TARGET='$LDFLAGS'" || (cat testsuite/libffi.log && exit 1)
RUNTESTFLAGS="LDFLAGS_FOR_TARGET='$LDFLAGS $EXTRA_TEST_LDFLAGS'" || (cat testsuite/libffi.log && exit 1)

View File

@ -407,6 +407,10 @@ proc libffi_target_compile { source dest type options } {
lappend options "libs= -lpthread"
}
if { [string match "*-*-freebsd*" $target_triplet] } {
lappend options "libs= -lpthread"
}
lappend options "libs= -lffi"
if { [string match "aarch64*-*-linux*" $target_triplet] } {

View File

@ -28,7 +28,7 @@ closure_test_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
closure_test_fn(*(Dbls*)args[0]);
}
int main(int argc __UNUSED__, char** argv __UNUSED__)
int main(void)
{
ffi_cif cif;

View File

@ -216,8 +216,7 @@ cls_large_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __
ui8_5, si8_5);
}
int
main(int argc __UNUSED__, const char** argv __UNUSED__)
int main (void)
{
void *code;
ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);

View File

@ -8,7 +8,7 @@
#define NUM_THREADS 20
#ifdef _POSIX_BARRIERS
#if defined(_POSIX_BARRIERS) && _POSIX_BARRIERS > 0
pthread_barrier_t barrier;
#endif
@ -21,7 +21,7 @@ void callback(ffi_cif *cif __UNUSED__, void *ret, void **args, void *userdata __
}
void *thread_func(void *arg) {
#ifdef _POSIX_BARRIERS
#if defined(_POSIX_BARRIERS) && _POSIX_BARRIERS > 0
pthread_barrier_wait(&barrier);
#endif
@ -50,7 +50,7 @@ void *thread_func(void *arg) {
int main() {
pthread_t threads[NUM_THREADS];
#ifdef _POSIX_BARRIERS
#if defined(_POSIX_BARRIERS) && _POSIX_BARRIERS > 0
pthread_barrier_init(&barrier, NULL, NUM_THREADS);
#endif
@ -65,7 +65,7 @@ int main() {
pthread_join(threads[i], NULL);
}
#ifdef _POSIX_BARRIERS
#if defined(_POSIX_BARRIERS) && _POSIX_BARRIERS > 0
pthread_barrier_destroy(&barrier);
#endif