Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ dnl Process this with autoconf to create configure

AC_PREREQ([2.68])

AC_INIT([libffi],[3.6.0],[http://github.com/libffi/libffi/issues])
AC_INIT([libffi],[3.7.1],[http://github.com/libffi/libffi/issues])
AC_CONFIG_HEADERS([fficonfig.h])

FFI_VERSION_STRING="3.5.2"
FFI_VERSION_NUMBER=30502
dnl Derive the version macros from AC_INIT so they cannot drift when the
dnl release version is bumped. FFI_VERSION_NUMBER encodes X.Y.Z as
dnl X*10000 + Y*100 + Z, ignoring any non-numeric suffix (e.g. -rc0).
FFI_VERSION_STRING="AC_PACKAGE_VERSION"
ffi_version_major=`echo "AC_PACKAGE_VERSION" | cut -d. -f1`
ffi_version_minor=`echo "AC_PACKAGE_VERSION" | cut -d. -f2 | sed 's/[[^0-9]].*//'`
ffi_version_micro=`echo "AC_PACKAGE_VERSION" | cut -d. -f3 | sed 's/[[^0-9]].*//'`
FFI_VERSION_NUMBER=`expr ${ffi_version_major:-0} \* 10000 + ${ffi_version_minor:-0} \* 100 + ${ffi_version_micro:-0}`
AC_SUBST(FFI_VERSION_STRING)
AC_SUBST(FFI_VERSION_NUMBER)

Expand Down
28 changes: 27 additions & 1 deletion include/ffi.h.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* -----------------------------------------------------------------*-C-*-
libffi @VERSION@
- Copyright (c) 2011, 2014, 2019, 2021, 2022, 2024, 2025 Anthony Green
- Copyright (c) 2011, 2014, 2019, 2021, 2022, 2024, 2025, 2026 Anthony Green
- Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.

Permission is hereby granted, free of charge, to any person
Expand Down Expand Up @@ -524,6 +524,32 @@ void ffi_call(ffi_cif *cif,
void *rvalue,
void **avalue);

/* Reusable call plans.

A plan captures a signature's argument placement once so that repeated
calls skip the per-call work that ffi_call would otherwise redo. Build one
with ffi_call_plan_alloc, invoke it as many times as you like, and release
it with ffi_call_plan_free.

The plan is opaque and caller-owned. The cif must outlive the plan.
ffi_call_plan_alloc returns NULL only on allocation failure; a signature
with no fast path is still valid and ffi_call_plan_invoke falls back to
ffi_call for it. A plan is immutable once built, so it may be shared and
invoked concurrently from multiple threads. */
typedef struct ffi_call_plan ffi_call_plan;

FFI_API
ffi_call_plan *ffi_call_plan_alloc (ffi_cif *cif);

FFI_API
void ffi_call_plan_invoke (ffi_call_plan *plan,
void (*fn)(void),
void *rvalue,
void **avalue);

FFI_API
void ffi_call_plan_free (ffi_call_plan *plan);

FFI_API
ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
size_t *offsets);
Expand Down
2 changes: 1 addition & 1 deletion libffi-clib.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.12
name: libffi-clib
version: 3.6.0
version: 3.7.1
synopsis: libffi clibs
description: C source code for the libffi package
license: MIT
Expand Down
27 changes: 23 additions & 4 deletions src/aarch64/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,13 @@ extend_integer_type (void *source, int type)
}
}

#if defined(_MSC_VER)
#if defined(_MSC_VER) && !defined(__clang__)
void extend_hfa_type (void *dest, void *src, int h);
#else
static void
extend_hfa_type (void *dest, void *src, int h)
{
ssize_t f = h - AARCH64_RET_S4;
ptrdiff_t f = h - AARCH64_RET_S4;
void *x0;

#define BTI_J "hint #36"
Expand Down Expand Up @@ -449,7 +449,7 @@ extend_hfa_type (void *dest, void *src, int h)
}
#endif

#if defined(_MSC_VER)
#if defined(_MSC_VER) && !defined(__clang__)
void* compress_hfa_type (void *dest, void *src, int h);
#else
static void *
Expand Down Expand Up @@ -550,7 +550,9 @@ allocate_int128_to_reg_or_stack (struct call_context *context,
ngrn += ngrn & 1;
#endif

if (ngrn < N_X_ARG_REG)
/* The value must fit entirely in registers, i.e. the low half may
not be allocated to x7 with the high half spilled to the stack. */
if (ngrn + 2 <= N_X_ARG_REG)
{
ret = &context->x[ngrn];
ngrn += 2;
Expand Down Expand Up @@ -642,6 +644,23 @@ ffi_prep_cif_machdep (ffi_cif *cif)
break;
}

/* Composites larger than 16 bytes (that are not HFAs) are passed by
invisible reference: ffi_call copies the payload into the argument
slab (next_struct_area, growing down) and, once the X registers are
exhausted, also spills the by-ref pointer into the same slab (the
NSAA, growing up). The generic prep_cif accounting in cif->bytes
only charges the payload copy, not that 8-byte pointer slot, so the
two regions can collide and a later struct copy can overwrite an
already-spilled pointer with the copied payload bytes. Reserve an
extra 8 bytes per such argument so the slab is always large enough
for both. */
for (i = 0, n = cif->nargs; i < n; i++)
{
ffi_type *ty = cif->arg_types[i];
if (ty->size > 16 && !is_vfp_type (ty))
bytes += 8;
}

/* Round the stack up to a multiple of the stack alignment requirement. */
cif->bytes = (unsigned) FFI_ALIGN(bytes, 16);
cif->flags = flags;
Expand Down
2 changes: 1 addition & 1 deletion src/alpha/ffi.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2012 Anthony Green
ffi.c - Copyright (c) 2012, 2026 Anthony Green
Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.

Alpha Foreign Function Interface
Expand Down
2 changes: 1 addition & 1 deletion src/alpha/ffitarget.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 2012 Anthony Green
ffitarget.h - Copyright (c) 2012, 2026 Anthony Green
Copyright (c) 1996-2003 Red Hat, Inc.
Target configuration macros for Alpha.

Expand Down
2 changes: 1 addition & 1 deletion src/closures.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
closures.c - Copyright (c) 2019, 2022 Anthony Green
closures.c - Copyright (c) 2019, 2022, 2026 Anthony Green
Copyright (c) 2007, 2009, 2010 Red Hat, Inc.
Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
Expand Down
4 changes: 2 additions & 2 deletions src/dlmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1916,8 +1916,8 @@ static FORCEINLINE void x86_clear_lock(int* sl) {
#define CLEAR_LOCK(sl) x86_clear_lock(sl)

#else /* Win32 MSC */
#define CAS_LOCK(sl) interlockedexchange(sl, (LONG)1)
#define CLEAR_LOCK(sl) interlockedexchange (sl, (LONG)0)
#define CAS_LOCK(sl) interlockedexchange((LONG volatile *)(sl), (LONG)1)
#define CLEAR_LOCK(sl) interlockedexchange ((LONG volatile *)(sl), (LONG)0)

#endif /* ... gcc spins locks ... */

Expand Down
2 changes: 1 addition & 1 deletion src/frv/ffi.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (C) 2004 Anthony Green
ffi.c - Copyright (C) 2004, 2026 Anthony Green
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2008 Red Hat, Inc.

Expand Down
2 changes: 1 addition & 1 deletion src/ia64/ffi.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc.
Copyright (c) 2000 Hewlett Packard Company
Copyright (c) 2011 Anthony Green
Copyright (c) 2011, 2026 Anthony Green

IA64 Foreign Function Interface

Expand Down
14 changes: 11 additions & 3 deletions src/m32r/ffi.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2004 Renesas Technology
Copyright (c) 2008 Red Hat, Inc.
Copyright (c) 2022 Anthony Green
Copyright (c) 2022, 2026 Anthony Green

M32R Foreign Function Interface

Expand Down Expand Up @@ -180,10 +180,10 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
extended_cif ecif;
ffi_type **arg_types = cif->arg_types;
void **avalue_copy = NULL;
int i, nargs = cif->nargs;

ecif.cif = cif;
ecif.avalue = avalue;

/* If the return value is a struct and we don't have
a return value address then we need to make one. */
Expand All @@ -196,18 +196,26 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
ecif.rvalue = rvalue;

/* If we have any large structure arguments, make a copy so we are passing
by value. */
by value. The pointer array is cloned first: the caller owns avalue[]
and may reuse it for another call, so it must not be modified. */
for (i = 0; i < nargs; i++)
{
ffi_type *at = arg_types[i];
int size = at->size;
if (at->type == FFI_TYPE_STRUCT && size > 4)
{
char *argcopy = alloca (size);
if (avalue_copy == NULL)
{
avalue_copy = alloca (nargs * sizeof (void *));
memcpy (avalue_copy, avalue, nargs * sizeof (void *));
avalue = avalue_copy;
}
memcpy (argcopy, avalue[i], size);
avalue[i] = argcopy;
}
}
ecif.avalue = avalue;

switch (cif->abi)
{
Expand Down
14 changes: 11 additions & 3 deletions src/moxie/ffi.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (C) 2012, 2013, 2018, 2021, 2022 Anthony Green
ffi.c - Copyright (C) 2012, 2013, 2018, 2021, 2022, 2026 Anthony Green

Moxie Foreign Function Interface

Expand Down Expand Up @@ -129,10 +129,10 @@ void ffi_call(ffi_cif *cif,
{
extended_cif ecif;
ffi_type **arg_types = cif->arg_types;
void **avalue_copy = NULL;
int i, nargs = cif->nargs;

ecif.cif = cif;
ecif.avalue = avalue;

/* If the return value is a struct and we don't have a return */
/* value address then we need to make one */
Expand All @@ -146,18 +146,26 @@ void ffi_call(ffi_cif *cif,
ecif.rvalue = rvalue;

/* If we have any large structure arguments, make a copy so we are passing
by value. */
by value. The pointer array is cloned first: the caller owns avalue[]
and may reuse it for another call, so it must not be modified. */
for (i = 0; i < nargs; i++)
{
ffi_type *at = arg_types[i];
int size = at->size;
if (at->type == FFI_TYPE_STRUCT) /* && size > 4) All struct args?? */
{
char *argcopy = alloca (size);
if (avalue_copy == NULL)
{
avalue_copy = alloca (nargs * sizeof (void *));
memcpy (avalue_copy, avalue, nargs * sizeof (void *));
avalue = avalue_copy;
}
memcpy (argcopy, avalue[i], size);
avalue[i] = argcopy;
}
}
ecif.avalue = avalue;

switch (cif->abi)
{
Expand Down
11 changes: 10 additions & 1 deletion src/or1k/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
int i;
int size;
ffi_type **arg;
void **avalue_copy = NULL;

/* Calculate size to allocate on stack */

Expand All @@ -135,13 +136,21 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
size += 8;

/* If we have any large structure arguments, make a copy so we are passing
by value. */
by value. The pointer array is cloned first: the caller owns
avalue[] and may reuse it for another call, so it must not be
modified. */
{
ffi_type *at = cif->arg_types[i];
int size = at->size;
if (at->type == FFI_TYPE_STRUCT) /* && size > 4) All struct args? */
{
char *argcopy = alloca (size);
if (avalue_copy == NULL)
{
avalue_copy = alloca (cif->nargs * sizeof (void *));
memcpy (avalue_copy, avalue, cif->nargs * sizeof (void *));
avalue = avalue_copy;
}
memcpy (argcopy, avalue[i], size);
avalue[i] = argcopy;
}
Expand Down
31 changes: 27 additions & 4 deletions src/pa/ffi.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - (c) 2011 Anthony Green
ffi.c - (c) 2011, 2026 Anthony Green
(c) 2008 Red Hat, Inc.
(c) 2006 Free Software Foundation, Inc.
(c) 2003-2004 Randolph Chung <tausq@debian.org>
Expand Down Expand Up @@ -280,9 +280,24 @@ static void ffi_size_stack_pa32(ffi_cif *cif)

#ifdef PA_HPUX
case FFI_TYPE_LONGDOUBLE:
z += 1; /* passed by pointer, like a large struct */
break;
#endif

case FFI_TYPE_STRUCT:
z += 1; /* pass by ptr, callee will copy */
/* This must mirror the slot accounting in ffi_prep_args_pa32:
structs of 1-4 bytes occupy one slot, structs of 5-8 bytes are
passed inline in two even-aligned slots (exactly like a 64-bit
value), and larger structs are passed by pointer in one slot.
z stays offset from the marshaller's slot by FIRST_ARG_SLOT (odd),
so (z & 1) tracks the same alignment the marshaller applies. */
{
size_t len = (*ptr)->size;
if (len <= 4 || len > 8)
z += 1;
else
z += 2 + (z & 1);
}
break;

default: /* <= 32-bit values */
Expand Down Expand Up @@ -363,23 +378,31 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
extended_cif ecif;
size_t i, nargs = cif->nargs;
ffi_type **arg_types = cif->arg_types;
void **avalue_copy = NULL;

ecif.cif = cif;
ecif.avalue = avalue;

/* If we have any large structure arguments, make a copy so we are passing
by value. */
by value. The pointer array is cloned first: the caller owns avalue[]
and may reuse it for another call, so it must not be modified. */
for (i = 0; i < nargs; i++)
{
ffi_type *at = arg_types[i];
int size = at->size;
if (at->type == FFI_TYPE_STRUCT && size > 8)
{
char *argcopy = alloca (size);
if (avalue_copy == NULL)
{
avalue_copy = alloca (nargs * sizeof (void *));
memcpy (avalue_copy, avalue, nargs * sizeof (void *));
avalue = avalue_copy;
}
memcpy (argcopy, avalue[i], size);
avalue[i] = argcopy;
}
}
ecif.avalue = avalue;

/* If the return value is a struct and we don't have a return
value address then we need to make one. */
Expand Down
Loading
Loading