diff -r f1993a64f66c -r 14e513529ca5 erts/configure.in
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -538,6 +538,7 @@ AC_CHECK_LIB(dl, dlopen)
 AC_CHECK_LIB(dl, dlopen)
 AC_CHECK_LIB(inet, main)
 AC_CHECK_LIB(util, openpty)
+AC_CHECK_LIB(ffi, ffi_prep_cif)
 
 dnl Try to find a thread library.
 dnl
diff -r f1993a64f66c -r 14e513529ca5 erts/emulator/Makefile.in
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -695,7 +695,7 @@ RUN_OBJS = \
 	$(OBJDIR)/erl_term.o 		$(OBJDIR)/erl_node_tables.o \
 	$(OBJDIR)/erl_monitors.o	$(OBJDIR)/erl_process_dump.o \
 	$(OBJDIR)/erl_obsolete.o	$(OBJDIR)/erl_bif_timer.o \
-	$(OBJDIR)/erl_port_task.o
+	$(OBJDIR)/erl_port_task.o       $(OBJDIR)/erl_bif_ffi.o
 
 ifeq ($(TARGET),win32)
 DRV_OBJS = \
diff -r f1993a64f66c -r 14e513529ca5 erts/emulator/beam/atom.names
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -54,6 +54,33 @@ atom nocatch
 atom nocatch
 atom undefined_function
 atom undefined_lambda
+
+#
+# FFI atoms.
+#
+atom uchar
+atom schar
+atom ushort
+atom sshort
+atom uint
+atom sint
+atom ulong
+atom slong
+atom uint8
+atom sint8
+atom uint16
+atom sint16
+atom uint32
+atom sint32
+atom uint64
+atom sint64
+atom float
+atom double
+atom longdouble
+atom pointer
+atom size_t
+atom ssize_t
+atom void
 
 #
 # All other atoms.  Try to keep the order alphabetic.
diff -r f1993a64f66c -r 14e513529ca5 erts/emulator/beam/bif.tab
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -686,3 +686,8 @@ bif erlang:old_binary_to_term/1
 #
 #bif erlang:concat_binary/1
 #bif erlang:info/1
+
+#
+# FFI BIFs
+#
+bif ffi:call/3
diff -r f1993a64f66c -r 14e513529ca5 erts/emulator/beam/erl_bif_ffi.c
--- /dev/null
+++ b/erts/emulator/beam/erl_bif_ffi.c
@@ -0,0 +1,638 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ * 
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * The Initial Developer of the Original Code is CRS4 - Center for
+ * Advanced Studies, Research and Development in Sardinia
+ * (http://www.crs4.it/). All Rights Reserved.''
+ * 
+ *     $Id$
+ */
+/* Foreign Function Interface (FFI) for Erlang/OTP
+ *
+ * Copyright (C) 2007 by CRS4 - http://www.crs4.it/
+ * Author: Alceste Scalas <alceste@crs4.it>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include "sys.h"
+#include "erl_vm.h"
+#include "global.h"
+#include "erl_binary.h"
+#include "erl_process.h"
+#include "error.h"
+#include "bif.h"
+#include "atom.h"
+#include "big.h"
+#include "erl_bits.h"
+#include "erl_bif_ffi.h"
+
+#ifndef HAVE_LIBFFI
+
+/* 
+ * Since libffi is not supported, we always return an error when using
+ * one of the FFI BIFs
+ */
+BIF_RETTYPE ffi_call_3(BIF_ALIST_3)
+{
+    /* FIXME: a more descriptive error is definitely required */
+    BIF_ERROR(BIF_P, BADARG);
+}
+
+#else /* HAVE_LIBFFI */
+
+/*
+ * FFI type conversion table
+ */
+typedef struct {
+    Eterm name;
+    ffi_type *ftype;
+} FFIConversion;
+
+/* Floating point and unsized types come first (it's some sort of
+ * optimization for frequent usages) */
+static FFIConversion conversion_table[] = {
+    {am_float, &ffi_type_float},
+    {am_double, &ffi_type_double},
+    {am_uint, &ffi_type_uint},
+    {am_sint, &ffi_type_sint},
+    {am_pointer, &ffi_type_pointer},
+    {am_ushort, &ffi_type_ushort},
+    {am_sshort, &ffi_type_sshort},
+    {am_ulong, &ffi_type_ulong},
+    {am_slong, &ffi_type_slong},
+    {am_uchar, &ffi_type_uchar},
+    {am_schar, &ffi_type_schar},
+    {am_void, &ffi_type_void},
+    {am_uint8, &ffi_type_uint8},
+    {am_sint8, &ffi_type_sint8},
+    {am_uint16, &ffi_type_uint16},
+    {am_sint16, &ffi_type_sint16},
+    {am_uint32, &ffi_type_uint32},
+    {am_sint32, &ffi_type_sint32},
+    {am_uint64, &ffi_type_uint64},
+    {am_sint64, &ffi_type_sint64},
+    {am_longdouble, &ffi_type_longdouble},
+
+    /* We could create new FFI types for size_t et al., but that's easier */
+    {am_size_t, ((sizeof(size_t) == sizeof(Uint32))
+                ? &ffi_type_uint32 : &ffi_type_uint64)},
+    {am_ssize_t, ((sizeof(ssize_t) == sizeof(Sint32))
+                 ? &ffi_type_sint32 : &ffi_type_sint64)},
+
+    {am_false, NULL} /* Keep this at the end of the array */
+};
+
+/*
+ * Forward declarations
+ */
+static int build_ffi_args_array(Eterm args[], ffi_type *ffi_types[], byte *buf,
+                                void *call_ptrs[], Uint n);
+static Eterm build_ffi_return_term(Process *p, ffi_type *rtype, byte *retval);
+static char *pick_list_or_atom(Eterm name_term);
+static Port *id_or_name2port(Process *c_p, Eterm id);
+Eterm erts_make_signed_integer(Sint x, Process *p);
+
+/*
+ * Call the given C function.  The function parameters are in the form:
+ *
+ *    Port, {Fn, Arg1, Arg2, ...}, {RetType, Arg1Type, Arg2Type, ...}
+ *
+ * where Port is an open port, Fn is an atom representing the function
+ * name, and Arg1... are the function arguments.  RetType is the C
+ * function return type, while Arg1Type...  are the C types of the
+ * function call arguments.
+ */
+BIF_RETTYPE ffi_call_3(BIF_ALIST_3)
+{
+    Port* p;
+    void* handle;
+    void* fptr;
+    Eterm *calltp, *typestp;
+    Uint nargs;
+    char *fname = NULL;
+    Eterm res;
+    int status = 0; /* Will possibly contain internal error codes */
+
+    p = id_or_name2port(BIF_P, BIF_ARG_1);
+    if (!p) {
+    error:
+        if (fname != NULL)
+            erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) fname);
+        BIF_ERROR(BIF_P, BADARG);
+    }
+
+    if (is_not_tuple(BIF_ARG_2) || is_not_tuple(BIF_ARG_3))
+        goto error;
+    
+    calltp = tuple_val(BIF_ARG_2);
+    typestp = tuple_val(BIF_ARG_3);
+    /* The call and arguments tuples must have the same lengths */
+    if (calltp[0] != typestp[0])
+        goto error;
+    nargs = arityval(calltp[0]);
+    if (nargs < 1)
+	goto error;
+
+    /* Skip tuple lengths, we don't need them anymore */
+    ++typestp;
+    ++calltp;
+
+    /* FIXME: is the following check really necessary? */
+    if (!p->drv_ptr)
+        goto error; /* The port is not associated to a driver */    
+    /* FIXME: is it possible that drv_ptr->handle is NULL? */
+    handle = ((DE_Handle*) p->drv_ptr->handle)->handle;
+
+    /* Extract function name from the first tuple element... */
+    if ((fname = pick_list_or_atom(calltp[0])) == NULL)
+        goto error;
+    /* ...and finally get function pointer */
+    if ((fptr = driver_dl_sym(handle, fname)) == NULL)
+        goto error;
+
+    {
+        Sint64 retval[2]; /* FFI call return value (must be large & aligned) */
+        ffi_cif cif;
+        ffi_type* ftypes[nargs]; /* Return type + call arguments types */
+        void* avalues[nargs - 1]; /* Pointers to arguments data */
+        byte buf[ERL_FFI_ARGS_BUF_SIZE]; /* Buffer for FFI arguments */
+
+        /* Prepare the FFI function call... */
+        if ((status = erl_ffi_build_types_array(typestp, ftypes, nargs)))
+            goto late_error;
+        if ((status = build_ffi_args_array(calltp+1, ftypes+1, buf, avalues,
+                                            nargs-1)))
+            goto late_error;
+
+        if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs - 1,
+                         ftypes[0], ftypes+1) != FFI_OK) {
+	    status = ERL_FFI_STATUS_FFI_ERROR;
+            goto late_error;
+	}
+        /* ...and actually perform the call */
+        ffi_call(&cif, fptr, &retval, avalues);
+
+        /* Now figure out what to do with the return value */
+        res = build_ffi_return_term(BIF_P, ftypes[0], (byte*)retval);
+    }
+
+    BIF_RET(res);
+
+    late_error:
+    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) fname);
+    switch (status) {
+    case ERL_FFI_STATUS_BADARG:
+	BIF_ERROR(BIF_P, BADARG);
+    case ERL_FFI_STATUS_BUG:
+    case ERL_FFI_STATUS_FFI_ERROR:
+	BIF_ERROR(BIF_P, EXC_INTERNAL_ERROR);
+    case ERL_FFI_STATUS_TOO_MANY_ARGS:
+	BIF_ERROR(BIF_P, EXC_SYSTEM_LIMIT);
+    default:
+	/* It should never happen */
+	BIF_ERROR(BIF_P, EXC_INTERNAL_ERROR);
+    }
+}
+
+/* Fill the given array of ffi_type pointers with proper values, based
+ * on the given array of Erlang terms.  'n' is the number of elements
+ * of the arrays.  Return 0 on success, something else on error. */
+int erl_ffi_build_types_array(Eterm types[], ffi_type *ftypes[], Uint n)
+{
+    Uint i;
+    Eterm tname;
+    FFIConversion *conv;
+
+    for (i = 0; i < n; ++i) {
+        tname = types[i];
+
+        if (is_not_atom(tname))
+            return ERL_FFI_STATUS_BADARG;
+
+        for (conv = conversion_table; conv->name != am_false; ++conv) {
+            if (conv->name == tname) {
+                ftypes[i] = conv->ftype;
+                break;
+            }
+        }
+        if (conv->name == am_false) {
+            /* Type was invalid */
+            return ERL_FFI_STATUS_BADARG;
+        }
+    }
+
+    return ERL_FFI_STATUS_OK;
+}
+
+/* Fill 'call_ptrs' with proper pointers, based on the given array of
+ * Erlang terms representing FFI call arguments.  'n' is the number of
+ * elements of the arrays.  'buf' is used as storage for data that
+ * needs to be copied.  Return 0 on success, something else on
+ * error. */
+static int build_ffi_args_array(Eterm args[], ffi_type *ffi_types[],
+                                byte *buf, void *call_ptrs[], Uint n)
+{
+    Uint i, offset = 0;
+    FloatDef f;
+    ffi_type* ftype;
+    Eterm arg, unused1, unused2;
+    byte* ptr;
+    int tmpint;
+    long tmplong;
+    Sint32 tmps32;
+    Sint64 tmps64;
+
+    for (i = 0; i < n; ++i) {
+        
+        if (offset > ERL_FFI_ARGS_BUF_SIZE)
+            return ERL_FFI_STATUS_TOO_MANY_ARGS;
+
+        ftype = ffi_types[i];
+        arg = args[i];
+        if (ftype == &ffi_type_float) {
+            if (is_not_float(arg))
+                return -1;
+            GET_DOUBLE(arg, f);
+            *((float*)buf) = (float)f.fd;
+            call_ptrs[i] = buf;
+            offset += sizeof(float);
+            buf += sizeof(float);
+        } else if (ftype == &ffi_type_double) {
+            if (is_not_float(arg))
+                return ERL_FFI_STATUS_BADARG;
+            GET_DOUBLE(arg, f);
+            *((double*)buf) = f.fd;
+            call_ptrs[i] = buf;
+            offset += sizeof(double);
+            buf += sizeof(double);
+        } else if (ftype == &ffi_type_uint) {
+            /* Integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                *((unsigned int*) buf) = *((unsigned int*) ptr);
+            } else if (is_small(arg))
+                *((unsigned int*) buf) = unsigned_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(unsigned int);
+            buf += sizeof(unsigned int);
+        } else if (ftype == &ffi_type_sint) {
+            /* Integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                if (big_sign(arg)) {
+                    /* Erlang big integers keep a sign byte, instead of using
+                     * 2's complement */
+                    tmpint = -(*((int*)ptr));
+                    *((int*) buf) = tmpint;
+                } else
+                    *((int*) buf) = *((int*) ptr);
+            } else if (is_small(arg))
+                *((int*) buf) = signed_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(int);
+            buf += sizeof(int);
+        } else if (ftype == &ffi_type_pointer) {
+            /* Pointers may be taken either from binaries, smalls or bigs */
+            if (is_binary(arg))
+                ERTS_GET_BINARY_BYTES(arg, ptr, unused1, unused2);
+            else if (is_big(arg))
+                ptr = *((void**)big_v(arg));
+            else if (is_small(arg))
+                ptr = (void*)unsigned_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            *((void**)buf) = ptr;
+            call_ptrs[i] = buf;
+            offset += sizeof(void*);
+            buf += sizeof(void*);
+        } else if (ftype == &ffi_type_ushort) {
+            if (is_not_small(arg))
+                return ERL_FFI_STATUS_BADARG;
+            *((unsigned short*)buf) = (unsigned short)unsigned_val(arg);
+            call_ptrs[i] = buf;
+            offset += sizeof(unsigned short);
+            buf += sizeof(unsigned short);
+        } else if (ftype == &ffi_type_sshort) {
+            if (is_not_small(arg))
+                return ERL_FFI_STATUS_BADARG;
+            *((short*)buf) = (short)signed_val(arg);
+            call_ptrs[i] = buf;
+            offset += sizeof(short);
+            buf += sizeof(short);
+        } else if (ftype == &ffi_type_ulong) {
+            /* Long integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                *((unsigned long*) buf) = *((unsigned long*) ptr);
+            } else if (is_small(arg))
+                *((unsigned long*) buf) = unsigned_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(unsigned long);
+            buf += sizeof(unsigned long);
+        } else if (ftype == &ffi_type_slong) {
+            /* Integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                if (big_sign(arg)) {
+                    /* Erlang big integers keep a sign byte, instead of using
+                     * 2's complement */
+                    tmplong = -(*((long*)ptr));
+                    *((long*) buf) = tmplong;
+                } else
+                    *((long*) buf) = *((long*) ptr);
+            } else if (is_small(arg))
+                *((long*) buf) = signed_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(long);
+            buf += sizeof(long);
+        } else if (ftype == &ffi_type_uchar) {
+            /* This also applies for uint8 */
+            if (is_not_small(arg))
+                return ERL_FFI_STATUS_BADARG;
+            *((unsigned char*)buf) = unsigned_val(arg);
+            call_ptrs[i] = buf;
+            offset += sizeof(unsigned char);
+            buf += sizeof(unsigned char);
+        } else if (ftype == &ffi_type_schar) {
+            /* This also applies for sint8 */
+            if (is_not_small(arg))
+                return ERL_FFI_STATUS_BADARG;
+            *((char*)buf) = signed_val(arg);
+            call_ptrs[i] = buf;
+            offset += sizeof(char);
+            buf += sizeof(char);
+        } else if (ftype == &ffi_type_uint16) {
+            if (is_not_small(arg))
+                return ERL_FFI_STATUS_BADARG;
+            *((Uint16*)buf) = (Uint16)unsigned_val(arg);
+            call_ptrs[i] = buf;
+            offset += sizeof(Uint16);
+            buf += sizeof(Uint16);
+        } else if (ftype == &ffi_type_sint16) {
+            if (is_not_small(arg))
+                return ERL_FFI_STATUS_BADARG;
+            *((Sint16*)buf) = (Sint16)signed_val(arg);
+            call_ptrs[i] = buf;
+            offset += sizeof(Sint16);
+            buf += sizeof(Sint16);
+        } else if (ftype == &ffi_type_uint32) {
+            /* 32-bit integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                *((Uint32*) buf) = *((Uint32*) ptr);
+            } else if (is_small(arg))
+                *((Uint32*) buf) = (Uint32)unsigned_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(Uint32);
+            buf += sizeof(Uint32);
+        } else if (ftype == &ffi_type_sint32) {
+            /* 32-bit integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                if (big_sign(arg)) {
+                    /* Erlang big integers keep a sign byte, instead of using
+                     * 2's complement */
+                    tmps32 = -(*((Sint32*)ptr));
+                    *((Sint32*) buf) = tmps32;
+                } else
+                    *((Sint32*) buf) = *((Sint32*) ptr);
+            } else if (is_small(arg))
+                *((Sint32*) buf) = signed_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(Sint32);
+            buf += sizeof(Sint32);
+        } else if (ftype == &ffi_type_uint64) {
+            /* 64-bit integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                *((Uint64*) buf) = *((Uint64*) ptr);
+            } else if (is_small(arg))
+                *((Uint64*) buf) = unsigned_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(Uint64);
+            buf += sizeof(Uint64);
+        } else if (ftype == &ffi_type_sint64) {
+            /* Integers may be taken either from smalls or bigs */
+            if (is_big(arg)) {
+                ptr = (void*)big_v(arg);
+                if (big_sign(arg)) {
+                    /* Erlang big integers keep a sign byte, instead of using
+                     * 2's complement */
+                    tmps64 = -(*((Sint64*)ptr));
+                    *((Sint64*) buf) = tmps64;
+                } else
+                    *((Sint64*) buf) = *((Sint64*) ptr);
+            } else if (is_small(arg))
+                *((Sint64*) buf) = signed_val(arg);
+            else
+                return ERL_FFI_STATUS_BADARG;
+            call_ptrs[i] = buf;
+            offset += sizeof(Sint64);
+            buf += sizeof(Sint64);
+        } else if (ftype == &ffi_type_longdouble) {
+            if (is_not_float(arg))
+                return ERL_FFI_STATUS_BADARG;
+            GET_DOUBLE(arg, f);
+            *((long double*)buf) = (long double)f.fd;
+            call_ptrs[i] = buf;
+            offset += sizeof(long double);
+            buf += sizeof(long double);
+        } else {
+            /* It should never happen */
+            return ERL_FFI_STATUS_BUG;
+        }
+    }
+
+    return ERL_FFI_STATUS_OK;
+}
+
+/* Build an Erlang Term compatible with the given FFI return type and
+ * value */
+static Eterm build_ffi_return_term(Process* p, ffi_type* rtype, byte* retval)
+{
+    FloatDef f;
+    Eterm res;
+    Eterm* hp;
+    long tmplong;
+    unsigned long tmpulong;
+    Sint64 tmps64;
+    Uint64 tmpu64;
+
+    if (rtype == &ffi_type_void) {
+        return am_ok;
+    } else if (rtype == &ffi_type_float) {
+        f.fd = *((float*) retval);
+        hp = HAlloc(p, FLOAT_SIZE_OBJECT);
+        res = make_float(hp);
+        PUT_DOUBLE(f, hp);
+    } else if (rtype == &ffi_type_double) {
+        f.fd = *((double*) retval);
+        hp = HAlloc(p, FLOAT_SIZE_OBJECT);
+        res = make_float(hp);
+        PUT_DOUBLE(f, hp);
+    } else if (rtype == &ffi_type_uint) {
+        res = erts_make_integer(*((unsigned int*) retval), p);
+    } else if (rtype == &ffi_type_sint) {
+        res = erts_make_signed_integer(*((int*) retval), p);
+    } else if (rtype == &ffi_type_pointer) {
+        hp = ArithAlloc(p, 1 + WSIZE(sizeof(void*)));
+        res = bytes_to_big((byte*)retval, sizeof(void*), 0, hp);
+    } else if (rtype == &ffi_type_ushort) {
+        res = make_small(*((unsigned short*) retval));
+    } else if (rtype == &ffi_type_sshort) {
+        res = make_small(*((short*) retval));
+    } else if (rtype == &ffi_type_ulong) {
+        hp = ArithAlloc(p, 1 + WSIZE(sizeof(unsigned long)));
+        res = bytes_to_big((byte*)retval, sizeof(unsigned long), 0, hp);
+    } else if (rtype == &ffi_type_slong) {
+        hp = ArithAlloc(p, 1 + WSIZE(sizeof(long)));
+        tmplong = *((long*)retval);
+        if (tmplong >= 0)
+            res = bytes_to_big((byte*)&tmplong, sizeof(long), 0, hp);
+        else {
+            /* Erlang big integers keep a sign byte, instead of using
+             * 2's complement */
+            tmpulong = -tmplong;
+            res = bytes_to_big((byte*)&tmpulong, sizeof(long), 1, hp);
+        }
+    } else if (rtype == &ffi_type_uchar) {
+        /* It also applies for uint8 */
+        res = make_small(*((unsigned char*) retval));
+    } else if (rtype == &ffi_type_schar) {
+        /* It also applies for sint8 */
+        res = make_small(*((char*) retval));
+    } else if (rtype == &ffi_type_uint16) {
+        res = make_small(*((Uint16*) retval));
+    } else if (rtype == &ffi_type_sint16) {
+        res = make_small(*((Sint16*) retval));
+    } else if (rtype == &ffi_type_uint32) {
+        res = erts_make_integer(*((Uint32*) retval), p);
+    } else if (rtype == &ffi_type_sint32) {
+        res = erts_make_signed_integer(*((Sint32*) retval), p);
+    } else if (rtype == &ffi_type_uint64) {
+        hp = ArithAlloc(p, 1 + WSIZE(sizeof(Uint64)));
+        res = bytes_to_big((byte*)retval, sizeof(Uint64), 0, hp);
+    } else if (rtype == &ffi_type_sint64) {
+        hp = ArithAlloc(p, 1 + WSIZE(sizeof(Sint64)));
+        tmps64 = *((Sint64*)retval);
+        if (tmps64 >= 0)
+            res = bytes_to_big((byte*)&tmps64, sizeof(Sint64), 0, hp);
+        else {
+            /* Erlang big integers keep a sign byte, instead of using
+             * 2's complement */
+            tmpu64 = -tmps64;
+            res = bytes_to_big((byte*)&tmpu64, sizeof(Sint64), 1, hp);
+        }
+    } else if (rtype == &ffi_type_longdouble) {
+        /* Sorry, we must truncate the long double into a double */
+        f.fd = *((long double*) retval);
+        hp = HAlloc(p, FLOAT_SIZE_OBJECT);
+        res = make_float(hp);
+        PUT_DOUBLE(f, hp);
+    } else {
+        /* It should never happen */
+        BIF_ERROR(p, EXC_INTERNAL_ERROR);
+    }
+
+    return res;
+}
+
+/* FIXME: this is duplicated from erl_bif_ddll.c
+ *
+ * Anyway, the duplication allows to easily spot what kind of
+ * erts_free() is needed for freeing the returned buffer.
+ */
+static char *pick_list_or_atom(Eterm name_term)
+{ 
+    char *name = NULL;
+    int name_len;
+    if (is_atom(name_term)) {
+        Atom *ap = atom_tab(atom_val(name_term));
+        if (ap->len == 0) {
+            /* If io_lists with zero length is not allowed, 
+               then the empty atom shouldn't */
+            goto error;
+        }
+        name = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, ap->len + 1);
+        memcpy(name,ap->name,ap->len);
+        name[ap->len] = '\0';
+    } else {
+        name_len = io_list_len(name_term);
+        if (name_len <= 0) {
+            goto error;
+        }
+        name = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, name_len + 1);
+        if (io_list_to_buf(name_term, name, name_len) != 0) {
+            goto error;
+        }
+        name[name_len] = '\0';
+    }
+    return name;
+ error:
+    if (name != NULL) {
+        erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
+    }
+    return NULL;
+}
+
+/* FIXME: this is duplicated from erl_bif_port.c */
+static Port*
+id_or_name2port(Process *c_p, Eterm id)
+{
+    Port *port;
+    if (is_not_atom(id))
+        port = erts_id2port(id, c_p, ERTS_PROC_LOCK_MAIN);
+    else
+        erts_whereis_name(c_p, ERTS_PROC_LOCK_MAIN, id, NULL, 0, 0, &port);
+    return port;
+}
+
+/*
+** Create bigint on heap if necessary. Like the previously existing
+** make_small_or_big(), except for a HAlloc() instead of an
+** ArithAlloc().
+** NOTE: Only use erts_make_signed_integer(), when order of heap fragments is
+**       guaranteed to be correct.
+**
+* FIXME: it's almost duplicated from erts_make_integer in big.c
+*/
+Eterm
+erts_make_signed_integer(Sint x, Process *p)
+{
+    Eterm* hp;
+    if (IS_SSMALL(x))
+        return make_small(x);
+    else {
+        hp = HAlloc(p, BIG_UINT_HEAP_SIZE);
+        return small_to_big(x,hp);
+    }
+}
+
+#endif /* HAVE_LIBFFI */
diff -r f1993a64f66c -r 14e513529ca5 erts/emulator/beam/erl_bif_ffi.h
--- /dev/null
+++ b/erts/emulator/beam/erl_bif_ffi.h
@@ -0,0 +1,49 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ * 
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * The Initial Developer of the Original Code is CRS4
+ * (http://www.crs4.it/). All Rights Reserved.''
+ * 
+ *     $Id$
+ */
+/* Foreign Function Interface (FFI) for Erlang/OTP
+ *
+ * Copyright (C) 2007 by CRS4 - http://www.crs4.it/
+ * Author: Alceste Scalas <alceste@crs4.it>
+ */
+
+#ifndef __ERL_BIF_FFI_H__
+#define __ERL_BIF_FFI_H__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Buffer size used for storing FFI call arguments */
+#define ERL_FFI_ARGS_BUF_SIZE 512
+
+/* Some internal error statuses returned by FFI routines  */
+#define ERL_FFI_STATUS_OK            0
+#define ERL_FFI_STATUS_BADARG        -1
+#define ERL_FFI_STATUS_TOO_MANY_ARGS -2
+#define ERL_FFI_STATUS_FFI_ERROR     -3
+#define ERL_FFI_STATUS_BUG           -99
+
+#ifdef HAVE_LIBFFI
+
+#include <ffi.h>
+
+/* Function prototypes */
+int erl_ffi_build_types_array(Eterm types[], ffi_type *ftypes[],Uint n);
+
+#endif /* HAVE_LIBFFI */
+
+#endif /* __ERL_BIF_FFI_H__ */
