mirror of
https://github.com/libffi/libffi.git
synced 2026-01-27 18:34:06 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2263d6037f | ||
|
|
f067aef649 | ||
|
|
3276df05a7 | ||
|
|
d6005499c2 | ||
|
|
205fc530b0 | ||
|
|
2835f72cc7 | ||
|
|
170bab47c9 | ||
|
|
c3a2b65748 | ||
|
|
c9b2a8a4ce | ||
|
|
e2eda0cf72 | ||
|
|
b53b0042c2 | ||
|
|
20eacb22e9 | ||
|
|
b7885ace59 | ||
|
|
6067118768 | ||
|
|
d0f831bca6 | ||
|
|
e28a0d5b07 | ||
|
|
90220e51bc | ||
|
|
330467d55c | ||
|
|
517310ddbf | ||
|
|
d994395ce7 | ||
|
|
26d7be77cc | ||
|
|
a18d4e95d3 | ||
|
|
b9b8378556 | ||
|
|
7ac6f14591 | ||
|
|
ceab352dfa | ||
|
|
1f73aa507e | ||
|
|
7f5375d7c7 | ||
|
|
2a5195bb2a | ||
|
|
2f535b8f74 |
@ -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
|
||||
|
||||
@ -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 | \
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
BUILD-ERROR
|
||||
RUNTIME-ERROR
|
||||
FEATURE-REQUEST
|
||||
QUESTION
|
||||
|
||||
# Operating systems
|
||||
ANDROID
|
||||
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -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
|
||||
|
||||
61
.github/workflows/emscripten.yml
vendored
61
.github/workflows/emscripten.yml
vendored
@ -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
|
||||
|
||||
52
.github/workflows/tarball.yml
vendored
52
.github/workflows/tarball.yml
vendored
@ -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
|
||||
|
||||
@ -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 \
|
||||
|
||||
13
README.md
13
README.md
@ -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.
|
||||
|
||||
22
configure.ac
22
configure.ac
@ -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])
|
||||
;;
|
||||
|
||||
@ -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"
|
||||
;;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
7
src/riscv/internal.h
Normal 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 */
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
@ -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
|
||||
@ -41,9 +41,6 @@
|
||||
|
||||
#if defined (X86_64) && defined (__i386__)
|
||||
#undef X86_64
|
||||
#warning ******************************************************
|
||||
#warning ********** X86 IS DEFINED ****************************
|
||||
#warning ******************************************************
|
||||
#define X86
|
||||
#endif
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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/
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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] } {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user