diff -r 420dcc1dce80 -r ea389fb1ca84 erts/emulator/beam/erl_bif_ffi.c
--- a/erts/emulator/beam/erl_bif_ffi.c
+++ b/erts/emulator/beam/erl_bif_ffi.c
@@ -688,8 +688,20 @@ static int build_ffi_args_array(Eterm ar
         } 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);
+		ptr = (void*)big_v(arg);
+#ifndef ARCH_64
+		/* On 32-bit architectures, a 64-bit value may fit in
+		 * in a variable number of words. */
+		if (4 == big_size(arg) * sizeof(digit_t)) {
+		    /* It is a 32-bit value */
+		    *((Uint64*) buf) = (Uint64)(*((Uint32*) ptr));
+		} else {
+		    /* It is a 64-bit value */
+		    *((Uint64*) buf) = *((Uint64*) ptr);
+		}
+#else /* ARCH_64 */
                 *((Uint64*) buf) = *((Uint64*) ptr);
+#endif
             } else if (is_small(arg))
                 *((Uint64*) buf) = unsigned_val(arg);
             else
@@ -701,13 +713,40 @@ static int build_ffi_args_array(Eterm ar
             /* Integers may be taken either from smalls or bigs */
             if (is_big(arg)) {
                 ptr = (void*)big_v(arg);
+#ifndef ARCH_64
+		/* On 32-bit architectures, a 64-bit value may fit in
+		 * in a variable number of words. */
+		if (4 == big_size(arg) * sizeof(digit_t)) {
+		    /* It is a 32-bit value */
+		    if (big_sign(arg)) {
+			/* Erlang big integers keep a sign byte,
+			 * instead of using 2's complement */
+			tmps64 = -(*((Sint32*)ptr));
+			*((Sint64*) buf) = tmps64;
+		    } else {
+			*((Sint64*) buf) = *((Sint32*) ptr);
+		    }
+		} else {
+		    /* It is a 64-bit value */
+		    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 /* ARCH_64 */
                 if (big_sign(arg)) {
                     /* Erlang big integers keep a sign byte, instead of using
                      * 2's complement */
                     tmps64 = -(*((Sint64*)ptr));
                     *((Sint64*) buf) = tmps64;
-                } else
+                } else {
                     *((Sint64*) buf) = *((Sint64*) ptr);
+		}
+#endif
             } else if (is_small(arg))
                 *((Sint64*) buf) = signed_val(arg);
             else
@@ -802,6 +841,9 @@ static Eterm build_ffi_return_term(Proce
     unsigned long tmpulong;
     Sint64 tmps64;
     Uint64 tmpu64;
+#ifndef ARCH_64
+    Uint32 tmpu32;
+#endif
     ProcBin *pb;
     Binary *bin;
     byte *ptr;
@@ -825,30 +867,38 @@ static Eterm build_ffi_return_term(Proce
     } else if (rtype == &ffi_type_pointer
 	       || rtype == &erl_ffi_type_cstring
 	       || rtype == &erl_ffi_type_nonnull) {
-        hp = ArithAlloc(p, 1 + WSIZE(sizeof(void*)));
 	if ((rtype != &ffi_type_pointer) && (*((byte**)retval) == NULL)) {
 	    /* 'cstring' and 'nonnull' may not be NULL */
 	    /* FIXME: a more descriptive error is definitely needed */
 	    BIF_ERROR(p, BADARG);
 	}
-        res = bytes_to_big((byte*)retval, sizeof(void*), 0, hp);
+	/* A pointer alwais fits in a Uint */
+        res = erts_make_integer(*((Uint*) retval), p);
     } 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);
+	if (IS_USMALL(0, *((unsigned long*)retval))) {
+	    res = make_small(*((unsigned long*)retval));
+	} else {
+	    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);
+	if (IS_SSMALL(*((long*)retval))) {
+	    res = make_small(*((long*)retval));
+	} else {
+	    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 */
@@ -865,19 +915,67 @@ static Eterm build_ffi_return_term(Proce
     } 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);
+	tmpu64 = *((Uint64*)retval);
+	if (IS_USMALL(0, tmpu64)) {
+	    res = make_small(tmpu64);
+	} else {
+#ifndef ARCH_64
+	    /* On 32-bit architectures, a 64-bit value that does not
+	     * fit in a small int may require a variable number of words. */
+	    if (tmpu64 <= (Uint64)UINT32_MAX) {
+		/* A 32-bit big integer is enough */
+		hp = ArithAlloc(p, 1 + WSIZE(sizeof(Uint32)));
+		tmpu32 = (Uint32)tmpu64;
+		res = bytes_to_big((byte*)&tmpu32, 4, 0, hp);
+	    } else {
+		/* A 64-bit big integer is necessary */
+		hp = ArithAlloc(p, 1 + WSIZE(sizeof(Uint64)));
+		res = bytes_to_big((byte*)&tmpu64, 8, 0, hp);
+	    }
+#else /* ARCH_64 */
+	    hp = ArithAlloc(p, 1 + WSIZE(sizeof(Uint64)));
+	    res = bytes_to_big((byte*)&tmpu64, 8, 0, hp);
+#endif
+	}
     } 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);
-        }
+	tmps64 = *((Sint64*)retval);
+	if (IS_SSMALL(tmps64)) {
+	    res = make_small(tmps64);
+	} else {
+#ifndef ARCH_64
+	    /* On 32-bit architectures, a 64-bit value that does not
+	     * fit in a small int may require a variable number of words. */
+	    if (((tmps64 > 0) && (tmps64 <= (Sint64)UINT32_MAX))
+		|| ((tmps64 < 0) && (tmps64 >= -(Sint64)UINT32_MAX))) {
+		/* A 32-bit big integer is enough */
+		hp = ArithAlloc(p, 1 + WSIZE(sizeof(Sint32)));
+		if (tmps64 < 0) {
+		    tmpu32 = (Uint32)-tmps64;
+		    res = bytes_to_big((byte*)&tmpu32, 4, 1, hp);
+		} else {
+		    tmpu32 = (Uint32)tmps64;
+		    res = bytes_to_big((byte*)&tmpu32, 4, 0, hp);
+		}
+	    } else {
+		/* A 64-bit big integer is necessary */
+		hp = ArithAlloc(p, 1 + WSIZE(sizeof(Sint64)));
+		if (tmps64 < 0) {
+		    tmpu64 = (Uint64)-tmps64;
+		    res = bytes_to_big((byte*)&tmpu64, 8, 1, hp);
+		} else {
+		    res = bytes_to_big((byte*)&tmps64, 8, 0, hp);
+		}
+	    }
+#else /* ARCH_64 */
+	    hp = ArithAlloc(p, 1 + WSIZE(sizeof(Sint64)));
+	    if (tmps64 < 0) {
+		tmpu64 = (Uint64)-tmps64;
+		res = bytes_to_big((byte*)&tmpu64, 8, 1, hp);
+	    } else {
+		res = bytes_to_big((byte*)&tmps64, 8, 0, hp);
+	    }
+#endif
+	}
     } else if (rtype == &ffi_type_longdouble) {
         /* Sorry, we must truncate the long double into a double */
         f.fd = *((long double*) retval);
